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)]
0day
已有 8 条评论
漂亮的分析
非常屌!
锅锅,你的电脑不错哦
感觉很多的密码都在github中泄露的,。。真不知道他们怎么想的
建立数据库连接时出错
听说毛子黑客可以吊打facebook
竟然把调试信息都给别人看,这么低级的错误我不想说什么。