揭秘:从内部源码看Facebook技术(第一集)


发布人:admin分类:网络安全浏览量:27发布时间:2017-12-12

Warning

本文中所有代码都是通过合法途径获得。

写在前面

我是一名铁杆Facebook粉丝。Facebook为开源社区贡献了许多力量,经常开放他们内部的软件。比如Phabricator, libphutil, 以及 XHP都是不错的好东西。

Phabricator是Facebook开发的可视化代码审查工具。工程师可以在页面上非常方便的针对每一段(单行或者多行)代码进行交互讨论。负责审查的工程师可以接受代码改变,可以提出疑问要求原作者继续修改。

曾经有段时间我对Phabricator 和XHP(一个PHP扩展)进行了优化研究,却意外发现了许多有关Facebook的内部资料。

意外的发现

大概是2013年6月份左右,那时我已经在使用Phabricator修复bug了。如果我没有记错的话,Phabricator程序当时是返回了一个PhutilBootloaderException错误信息。

当时我并不知道Phabricator是怎么运行的,于是就Google查询了下错误信息……就跟你想的一样,我获得了源代码以及一些参考链接,其中有一个链接十分抢眼——一个Pastebin(一个轻量级的文本分享工具)分享链接,里面有Facebook很多的内部数据。

当然,这引起了我的兴趣,下面就是我的发现…

[emir@dev3003 ~/devtools/libphutil] arcdiff --trace
>>> [0] <conduit>conduit.connect()
<<< [0] <conduit> 98,172 us
>>> [1] <exec> $ (cd&'/home/emir/devtools/libphutil&'; git rev-parse --show-cdup)
<<< [1] <exec> 13,629 us
>>> [2] <exec> $ (cd&'/home/emir/devtools/libphutil/&'; git rev-parse --verify HEAD^)
<<< [2] <exec> 17,024 us
>>> [3] <exec> $ (cd&'/home/emir/devtools/libphutil/&'; git diff --no-ext-diff --no-textconv --raw&'HEAD^&' --)
>>> [4] <exec> $ (cd&'/home/emir/devtools/libphutil/&'; git diff --no-ext-diff --no-textconv --rawHEAD --)
>>> [5] <exec> $ (cd&'/home/emir/devtools/libphutil/&'; git ls-files --others --exclude-standard)
>>> [6] <exec> $ (cd&'/home/emir/devtools/libphutil/&'; git ls-files -m)
<<< [5] <exec> 73,004 us
<<< [6] <exec> 74,084 us
<<< [4] <exec> 77,907 us
<<< [3] <exec> 80,606 us
>>> [7] <exec> $ (cd&'/home/emir/devtools/libphutil/&'; git log --first-parent --format=medium&'HEAD^&'..HEAD)
<<< [7] <exec> 16,390 us
>>> [8] <conduit>differential.parsecommitmessage()
<<< [8] <conduit> 106,631 us
Linting...
>>> [9] <exec> $ (cd&'/home/emir/devtools/libphutil&'; git rev-parse --show-cdup)
<<< [9] <exec> 9,976 us
>>> [10] <exec> $ (cd&'/home/emir/devtools/libphutil/&'; git merge-base &'HEAD^&' HEAD)
<<< [10] <exec> 13,472 us
>>> [11] <exec> $ (cd&'/home/emir/devtools/libphutil/&'; git diff --no-ext-diff --no-textconv --raw&'00645a0aec09edc7f0f1f573032991ae94faa01b&' --)
>>> [12] <exec> $ (cd&'/home/emir/devtools/libphutil/&'; git diff --no-ext-diff --no-textconv --rawHEAD --)
>>> [13] <exec> $ (cd&'/home/emir/devtools/libphutil/&'; git ls-files --others --exclude-standard)
>>> [14] <exec> $ (cd&'/home/emir/devtools/libphutil/&'; git ls-files -m)
<<< [11] <exec> 19,092 us
<<< [14] <exec> 15,219 us
<<< [12] <exec> 21,602 us
<<< [13] <exec> 43,139 us
>>> [15] <exec> $ (cd&'/home/emir/devtools/libphutil/&'; git diff --no-ext-diff --no-textconv -M -C--no-color --src-prefix=a/ --dst-prefix=b/ -U32767&'00645a0aec09edc7f0f1f573032991ae94faa01b&' --)
<<< [15] <exec> 28,318 us
>>> [16] <exec> $&'/home/engshare/devtools/libphutil/src/parser/xhpast/bin/xhpast&' --version
<<< [16] <exec> 11,420 us
>>> [17] <exec> $&'/home/engshare/devtools/arcanist/scripts/phutil_analyzer.php&'&'/home/emir/devtools/libphutil/src/markup/engine/remarkup/markuprule/hyperlink&'
<<< [17] <exec> 490,196 us
>>> [18] <exec> $&'/home/engshare/devtools/arcanist/scripts/phutil_analyzer.php&'&'/home/engshare/devtools/libphutil/src/markup&'
>>> [19] <exec> $&'/home/engshare/devtools/arcanist/scripts/phutil_analyzer.php&'&'/home/engshare/devtools/libphutil/src/markup/engine/remarkup/markuprule/base&'
>>> [20] <exec> $&'/home/engshare/devtools/arcanist/scripts/phutil_analyzer.php&' &'/home/engshare/devtools/libphutil/src/parser/uri&'
>>> [21] <exec> $&'/home/engshare/devtools/arcanist/scripts/phutil_analyzer.php&'&'/home/engshare/devtools/libphutil/src/utils&'
<<< [18] <exec> 498,899 us
<<< [19] <exec> 497,710 us
<<< [20] <exec> 517,740 us
<<< [21] <exec> 556,267 us
>>> [22] <exec> $&'/home/engshare/devtools/libphutil/src/parser/xhpast/bin/xhpast&'
<<< [22] <exec> 10,066 us
 LINTOKAY  No lint problems.
Running unit tests...
HipHopFatal error: Uncaught exception exception &'PhutilBootloaderException&' withmessage &'The phutil library &'&' has not been loaded!&' in/home/engshare/devtools/libphutil/src/__phutil_library_init__.php:124nStacktrace:n#0 /home/engshare/devtools/libphutil/src/__phutil_library_init__.php(177):PhutilBootloader->getLibraryRoot()n#1/home/engshare/devtools/arcanist/src/unit/engine/phutil/PhutilUnitTestEngine.php(53):PhutilBootloader->moduleExists()n#2/home/engshare/devtools/arcanist/src/workflow/unit/ArcanistUnitWorkflow.php(113):PhutilUnitTestEngine->run()n#3/home/engshare/devtools/arcanist/src/workflow/diff/ArcanistDiffWorkflow.php(1172):ArcanistUnitWorkflow->run()n#4/home/engshare/devtools/arcanist/src/workflow/diff/ArcanistDiffWorkflow.php(225):ArcanistDiffWorkflow->runUnit()n#5/home/engshare/devtools/arcanist/scripts/arcanist.php(257):ArcanistDiffWorkflow->run()n#6 {main}

Okay,这确实不是完整的源码。这仅仅是一些命令行输出,但依旧告诉了我们一些有趣的信息。

数据分析

我们可以得知用户名“emir”,或许这是该用户的First Name(相当于国人的名),当然也可能是由姓的第一个字母加上名(E. Mir)。我们可以通过另外一个Facebook的工程师清楚的看到这些输出,所以在Pastebin上面发布文章不是一个明智的做法。这个人的这个做法很容易被攻击者盯住,惹来不必要的麻烦。

"dev3003"是emir那个时候使用的机器名字同时我们可以得知Facebook至少有3000台机器支持着开发工作假设“3003”是从1开始增长的,我对这个假设很确信呢)

`/home/engshare/devtools/`是libphutil和arcanist的安装路径,如果我的记忆没问题的话,`/home/engshare/`是通过NFS开发机器之间进行分享,这里没有什么比较有趣的,但是也有可能存在其他脚本定位在这个目录。

这里也有一些执行时间的信息,以及Git hashes。

之后,我又继续尝试类似Pastebin文章中的操作。结果告诉我,并没让我失望!

[25/10/2013]Promoting The Meme Bank (1/1) - Campaign Update Failed: Campaign 6009258279237:Value cannot be null (Value given: null)TAAL[BLAME_files,www/flib/core/utils/enforce.php,www/flib/core/utils/EnforceBase.php]

有趣的是,它显示了路径和文件名。"flib" (Facebook Library)是一个包含实用工具的内部lib以帮助开发。我们再深入一些…

[ksalas@dev578 ~/www]./scripts/intl/intl_string.php scan .
Loading modules, hang on...
Analyzing directory `.&'
Error: Command `ulimit -s 65536 &&/mnt/vol/engshare/tools/fbt_extractor -tasks 32 &'/data/users/ksalas/www-hg&'&'failed with error #2:
stdout:
 
stderr:
warning: parsing problem in/data/users/ksalas/www-hg/flib/intern/third-party/phpunit/phpunit/Tests/TextUI/dataprovider-log-xml-isolation.phpt
warning: parsing problem in/data/users/ksalas/www-hg/flib/intern/third-party/phpunit/phpunit/Tests/TextUI/dataprovider-log-xml.phpt
warning: parsing problem in /data/users/ksalas/www-hg/flib/intern/third-party/phpunit/phpunit/Tests/TextUI/log-xml.phpt
warning: parsing problem in/data/users/ksalas/www-hg/scripts/sandcastle/local_testing/script_for_test_commits.php
warning: parsing problem in/data/users/ksalas/www-hg/lib/arcanist/lint/linter/__tests__/hphpast/php-tags-script.lint-test
LEXER: unrecognised symbol, in token rule:&'
warning: parsing problem in/data/users/ksalas/www-hg/scripts/intern/test/test.php
warning: parsing problem in/data/users/ksalas/www-hg/scripts/intern/test/test2.php
Fatal error: exception Common.Todo
Fatal error: exceptionSys_error("Broken pipe")
 
 
Typeintl_string.php --help to get more information about how to use this script.

dev578中的Ksalas似乎在运行一个字符串解析器。`intl_string.php`尝试运行`/mnt/vol/engshare/tools/fbt_extractor`,所以我们可以知道在`/mnt/vol/engshare/`目录下还有其他的脚本,我们可以看到他们正在使用PHP Unit进行单元测试,"www-hg"是Mercurial的目录!众所周知,他们从Subversion进行Git迁移数据。

"That&'s still not god damn sourcecode!" 我听见有人在哭了……

Index: flib/core/db/queryf.php
===================================================================
--- flib/core/db/queryf.php
+++ flib/core/db/queryf.php
@@ -1104,11 +1104,12 @@
 *  @author rmcelroy
  */
 function mysql_query_all($sql, $ok_sql, $conn,$params) {
+ FBTraceDB::rqsend($ok_sql);
  switch (SQLQueryType::parse($sql)) {
    case SQLQueryType::READ:
      $t_start = microtime(true);
      $result = mysql_query_read($ok_sql, $conn);
      $t_end = microtime(true);
      $t_delta = $t_end - $t_start;
      if ($t_delta > ProfilingThresholds::$queryReadDuration) {
         ProfilingThresholds::recordDurationError(&'mysql.queryReadDuration&',

`flib/core/db/queryf.php`就是问题文件。在前面,我们认为这只是一个文件与另一个文件MySQL相关函数之间的差异。我们可以通过`mysql_query_all()`查询函数。从目前能够得到的代码看来,这是一个十分简单的查询函数,或许实际上它很复杂,但是不幸的是我们可能永远不会知道。

我会发布一些我发现的示例代码,这些都可以通过文章底部下载链接进行下载。

diff --gita/flib/entity/user/personal/EntPersonalUser.phpb/flib/entity/user/personal/EntPersonalUser.php
index 4de7ad8..439c162 100644
---a/flib/entity/user/personal/EntPersonalUser.php
+++b/flib/entity/user/personal/EntPersonalUser.php
@@ -306,13 +306,15 @@ class EntPersonalUserextends EntProfile
 
  public function prepareFriendIDs() {
    require_module_lazy(&'friends&');
-   // TODO: add privacy checks!
    DT(&'ReciprocalFriends&')->add($this->id);
    return null;
   }
 
  public function getFriendIDs() {
-   return DT(&'ReciprocalFriends&')->get($this->id);
+   if ($this->canSeeFriends()) {
+     return DT(&'ReciprocalFriends&')->get($this->id);
+   }
+   return array();
   }
 
  /**
@@ -397,6 +399,7 @@ class EntPersonalUserextends EntProfile
      $this->viewerCanSee,
      array(
        PrivacyConcepts::EXISTENCE,
+       PrivacyConcepts::FRIENDS,
        // Note that we&'re fetching GENDER here because it&'s PAI
        // so it&'s cheap and because we don&'t want to add a prepareGender
        // call here if we don&'t have to.
@@ -418,6 +421,10 @@ class EntPersonalUserextends EntProfile
    return must_prepare($this->viewerCanSee)->canSee();
   }
 
+ protected function canSeeFriends() {
+   return must_prepare($this->viewerCanSee)->canSeeFriends();
+  }
+
# update your local master branch
  gitcheckout master
  gitpull --rebase
 
# never do any work on master branch
# create & switch to new branch instead
  gitcheckout -b my_branch
 
# rebase &'my_branch&' onto master
  gitcheckout my_branch
  gitrebase master
 
# list branches
  gitbranch
 
# delete &'my_branch&' branch
  $git branch -d my_branch
 
# shows status
$ git status
 
stage file, also remove conflict
  $git add <file>
 
revert file to head revision
  $git checkout -- <file>
 
commit change
  $git commit -a --amend
   -a       stages all modified files
   --amend  overwrites last commit
 
show all local history (amend commits,branch changes, etc.)
  $git reflog
 
show history (there is lot of options)
  $git log
  $git log --pretty=oneline --abbrev-commit --author=plamenko
  $git log -S"text to search"
 
show last commit (what is about to be sendfor diff)
  $git show
 
get the version of the file from the givencommit
  $git checkout <commit> path/to/file 
 
fetch & merge
  $git pull --rebase
 
resolving conflicts:
  useours:
    $git checkout --ours index.html
  usetheirs:
    $git checkout --theirs index.html
 
commit author:
  $git config --global user.name "Ognjen Dragoljevic"
  $git config --global user.email plamenko@fb.com
 
 After doing this, you may fix the identity used for this commit with:
  $git commit --amend --reset-author
 
commit template:
 /mnt/vol/engshare/admin/scripts/templates/git-commit-template.txt
 
rename a branch:
  $git branch -m old_branch new_branch
 
interactive rebase
  $git rebase -i master
 pick
 edit
   make changes
   ...
    $git commit -a --amend
    $git rebase --continue
 exec
    $arc diff
    $arc amend
    $git push --dry-run origin HEAD:master // remove dry-run to do actual push
   ...
 
to update commit message in phabricator
  $ arc diff --verbatim
#!/bin/bash
#
# Creates a new www sandbox managed by git.
#
# Usage: git-clone-www [dirname]
#
# dirname defaults to "www-git".
#
 
DIRNAME=${1:-www-git}
 
NFS_REPO=/home/engshare/git/tfb
 
# Are we running on a machine that has alocal shared copy of the git repo?
if [ -d /data/git/tfb ]; then
  #Yes. Reuse its objects directory.
 echo "Cloning the local host&'s shared www repository..."
 PARENT=/data/git/tfb
 SHARE=-s
else
  #Nope, copy the NFS server&'s objects locally so as not to be dog slow.
 echo "Copying from the shared www repository on the NFSserver..."
 PARENT=$NFS_REPO
 SHARE=
fi
 
if [ ! -d $HOME/local ]; then
 echo "You don&'t seem to have a &'local&' symlink in your homedirectory."
 echo "Fix that and try again."
 exit 1
fi
 
cd $HOME/local
if [ -d "$DIRNAME" ]; then
 echo "You already have a $DIRNAME directory; won&'t overwriteit."
 echo "Aborting."
 exit 1
fi
 
# We clone the shared repository hererather than running "git svn clone"
# because it&'s much, much more efficient.And the clone has some options:
#
# -n = Don&'t check out working copy yet.
# -s = Reference the origin&'s .git/objectsdirectory rather than copying.
#     Saves gobs of disk space and makes the clone nearly instantaneous.
#     We don&'t do this if there&'s no local-disk shared repo.
 
git clone $SHARE -n "$PARENT""$DIRNAME"
 
cd "$DIRNAME"
 
# If we&'re sharing a local repository&'sobjects, use the NFS server as a
# fallback so stuff doesn&'t break if we usethis repo from another host
# that doesn&'t have a /data/git/tfbdirectory.
ALTERNATES=.git/objects/info/alternates
if [ -s $ALTERNATES ]; then
 echo $NFS_REPO/.git/objects >> $ALTERNATES
fi
 
# We want to use the same remote branchname ("remotes/trunk") for git-svn
# and for fetches from the shared git repo,so set that up explicitly.
git config remote.origin.url"file://$PARENT/.git"
git config remote.origin.fetchrefs/remotes/trunk:refs/remotes/trunk
git config --remove-section branch.master
 
# Enable the standard commit template
git config commit.template/home/engshare/admin/scripts/templates/git-commit-template.txt
 
# Enable recording of rebase conflictresolutions
git config rerere.enabled true
 
# Now fetch from the shared repo. Thismostly just creates the new "trunk"
# branch since we already have the objectsthanks to the initial "git clone".
git fetch origin
 
# Blow away the "origin/"branches created by "git clone" -- we don&'t need them.
rm -rf .git/refs/remotes/origin
 
# Now it&'s time to turn this plain old gitrepo into a git-svn repo. Really
# all we need is the svn-remoteconfiguration (installed above) and a
# metadata file with some versioninformation. git-svn is smart enough to
# rebuild the other stuff it needs.
 
echo ""
echo "Synchronizing with svn..."
 
git svn init -itrunksvn+ssh://tubbs/svnroot/tfb/trunk/www
 
# Now tweak the git-svn config a little bitso it&'s easier for someone to
# go add more "fetch" lines ifthey want to track svn-side branches in
# addition to trunk. This doesn&'t affectany of the existing history.
git config svn-remote.svn.urlsvn+ssh://tubbs/svnroot
git config svn-remote.svn.fetchtfb/trunk/www:refs/remotes/trunk
 
# Let git-svn update its mappings and fetchthe latest revisions. This can
# spew lots of uninteresting output sosuppress it.
git svn fetch > /dev/null
 
echo ""
echo "Checking out workingcopy..."
 
# We use git reset here because the git svnfetch might have advanced trunk
# to a newer revision than the masterbranch created by git clone.
git reset --hard trunk
 
if [ ! -d "$HOME/$DIRNAME" ];then
 echo ""
 echo "Making home dir symlink: $HOME/$DIRNAME"
  ln-s "local/$DIRNAME" "$HOME/$DIRNAME"
else
 echo ""
 echo "$HOME/$DIRNAME already exists; leaving it alone."
fi
 
echo ""
echo "All done. To make this your newmain sandbox directory, run"
echo ""
echo "    rm -rf ~/www"
echo "    ln -s ~/$DIRNAME ~/www"
echo""

Facebook MysSql数据库密码

最后,我想分享一些我认为有趣的东西。Facebook&'s MySQL password.似乎保存在`print_r()`数组

array( &'ip&' => &'10.21.209.92&', &'db_name&' => &'insights&', &'user&' => &'mark&',&'pass&' => &'e5p0nd4&', &'mode&' => &'r&', &'port&' => 3306, &'cleanup&' =>false, &'num_retries&' => 3, &'log_after_num_retries&' => 4, &'reason&' =>&'insights&', &'cdb&' => true, &'flags&' => 0, &'is_shadow&' => false,&'backoff_retry&' => false, )
Host: 10.21.209.92 (Private IP)
Database Name: insights
User: mark
Password:e5p0nd4

Okay,尽管Facebook数据库服务有大量防火墙进行保护,这也许不是最安全的密码。

学习收获

我们今天学到了什么呢?我们最好不要在面向公众的站点(就比如共享工具Pastebin)发布内部源码。另外还有一点:确保调试信息不会被用户看到。

下载地址

声明:仅供学习和研究用途

链接:http://pan.baidu.com/s/1kTEBXuJ 密码:p3ve
密码:freebuf.com

[参考来源Sinthetic Labs,译/实习编辑鸢尾,转载请注明来自Freebuf黑客与极客(FreeBuf.COM)]


被黑站点统计 - 文章版权1、本主题所有言论和图片纯属会员个人意见,与本文章立场无关
2、本站所有主题由该文章作者发表,该文章作者与被黑站点统计享有文章相关版权
3、其他单位或个人使用、转载或引用本文时必须同时征得该文章作者和被黑站点统计的同意
4、文章作者须承担一切因本文发表而直接或间接导致的民事或刑事法律责任
5、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
6、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除并致以最深的歉意
7、被黑站点统计管理员有权不事先通知发贴者而删除本文

免责声明

本站主要通过网络搜集国内被黑网站信息,统计分析数据,为部署安全型网络提供强有力的依据.本站所有工作人员均不参与黑站,挂马或赢利性行为,所有数据均为网民提供,提交者不一定是黑站人,所有提交采取不记名,先提交先审核的方式,如有任何疑问请及时与我们联系.

admin  的文章


微信公众号

微信公众号


Copyright © 2012-2022被黑网站统计系统All Rights Reserved
页面总访问量:21204651(PV) 页面执行时间:103.176(MS)
  • xml
  • 网站地图