笔者最近在挖某应用的漏洞时,恰好遇到了一个SSRF(Server Side Request Forgery)。该应用被托管在Amazon EC2上,项目里使用了Node.js和Express.js,后来我甚至还在上面发现了Needle.js。
手动发掘
在测试过程中,我注意到了该应用的某个函数。它会获取用户指定的URL,然后将该URL链接到的内容的第一段展示到当前页。这里讲一下,用户可以使用该应用分享一个URL给朋友们,这个小特性相当于预览文章的功能。
那么问题来了,当我查看Burp历史时,我找不到日志里指定的URL请求。我非常惊讶,因为这意味着服务器获取了我指定的URL,然后代我发请求,再返回结果给我,这儿恰巧有个SSRF。然而,最终我们还是看看风险点的确认。
自动化发掘
自2015年4月开始,如果你使用了 Burp Collaborator ,且把漏洞请求发送给主动扫描器,你应该就可以检测到SSRF。下图显示了几种Burp Collaborator甄别SSRF的不同方法(外部资源加载和扩展服务交互)。
攻击演示
我想证明该SSRF漏洞,但不能泄露关于该应用评测的详细信息。为了重现这个漏洞,我制作搭建了首个Node.js应用,关键是这玩意儿确实能用啊,应用地址如下:
https://github.com/sethsec/Nodejs-SSRF-App
我的demo应用托管在了Amazon EC2 micro instance上,在上面运行了Node.js,并且使用了Express.js和Needle.js。(这是SSRF请求的祸首)。
如真实环境那般,我的演示demo应用获取了用户指定的URL,然后由Needle.js发出请求。而真正的应用,则是通过检测请求包body里的JSON参数,从里面接收了用户指定的URL。然而我的Node代码水平有点着急,所以在演示时,我是通过GET请求发送数据的。
这是该漏洞演示应用最脆弱的一部分:
看起来像在执行:
它看起来像个iframe,不是么?但如果它是个普通的iframe的话,你的浏览器会请求ethsec.blogspot.com,该应用就不会有SSRF漏洞了。
当我尝试用存在漏洞的服务器去请求ifconfig.pro(查IP和User_Agent的网站)时,就可以确认SSRF漏洞的存在了:
这里最有意思的点还是源IP和User_Agent,来自ifconfig.pro的响应结果展示了来自EC2的请求,特别是来自Node.js的HTTP客户端Needle的。
风险点的所在
如上所述,让漏洞服务器帮你发送一个请求,就可以取到一些你没有能力直接获取的东西。
访问Amazon EC2元数据服务
比如你的应用在Amazon EC2上跑着,你可以通过它查询169.254.169.254(外部主机不可达)上的元数据服务。这台服务器只能通过该实例自己才能访问,所有没有SSRF、命令注入或者其他类似的漏洞,你是没可能接触到这个服务的。
这只是元数据对象的一个例子,Erik Peterson (@silvexis)发现了更多可从元数据服务里挖掘出的敏感信息,他的演讲视频如下 《Bringing a Machete to the Amazon》 。
比如,下面的请求就能让黑客临时获取admin权限的安全认证凭据,进而获取你的AWS资源。
访问你的Amazon EC2用户数据对象
另一个地方你可能也感兴趣,那就是用户数据容器,它位于http://169.254.169.254/latest/user-data,亚马逊给予了开发者警告:
http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html instancedata-add-user-data
但我们都知道,如果存储某些密码和其他敏感信息在用户数据里很方便的话,大家都会这样做。所以你可以从这方面下手,下面是我的漏洞实验EC2的请求:
如果你有权限去查询EC2元数据服务,这里给你提供一个完整的列表,请看下面这篇文档: 《Instance Metadata and User Data》
扫描和访问后端基础设施
除了检测元数据服务和用户数据外,你还应该利用SSRF寻找漏洞服务器所能直达的那些服务、主机和资源,而Burp Intruder对于这类攻击的实现非常有效。
Demo设置
为了设置demo,我又使用了一个EC2来跑kali,其内网IP为172.31.40.122并且监听8080端口,该主机上的WEB服务在公网是不可达的。事实上,它只有内网主机可达,也就是说我们需要SSRF去请求它的8080端口。
扫描端口(XSPA)
1.通过Burp发出初始请求,在这个案例中,我试图访问了TCP端口1。
2.发送初始请求到Burp Intruder。
3.设置payload位置(这里设定是端口)。
4.设置payload的内容,这个demo里我选择了连续的11个端口,但你可以设置nmap的前N个端口,或者常见的WEB服务端口。
5.启动攻击,你可以在下面的截图中看到。我们有一些法子可以推断哪些端口、哪些端口关闭。在这种情况下,你可以使用响应状态码或者响应包长度进行判断。
好吧,其实我这里只是为了证明172.31.40.122开着8080端口,而且正在运行WEB服务。
扫描主机
这里的步骤与上面的大概相同,只是这里不是把端口设定为payload,而是将想要扫描的IP地址制成一个列表。然后,用请求包里IP地址作为payload,固定请求80端口或者443端口进行扫描。
但是这里我就不扫描其他EC2的IP了,举个例子就行了。然而其实回到第四步,你会发现都差不多。
你可以使用Burp的Cluster Bomb选项,同时扫描端口和服务。
扫描内网WEB服务器
接下来,我将再次展示类似的流程。但这一次,我们要扫描的是服务器上的文件或者目录。
因为是演示嘛,所有我知道上面存在users.txt文件,所以直接把它放进了字典。当然,我还在里面填充了一些不相关的文件名,在实际场景中,你可能会使用如 fuzzdb 之类的资源。
如先前的例子那般,你可以通过匹配差异化的结果进行扫描。在这个例子中,所有的页面都会给你返回200的状态码。但是,访问user.txt的返回包长度比其他的都要短,这就是我们要寻找的差异化标志。
与上述的类似,你也可以用Cluster Bomb选项同时扫描多个WEB服务器的文件和目录。
修复建议
该应用需要检测用户输入的所有信息,而不是简单的直接去代理用户的请求。如果必须做代理的话,服务端应该做IP白名单,去除或者修改User-Agent信息。
额外的资源
这里有几个不错的SSRF资源,在我看来Nicolas Grégoire (@Agarri_FR)在SSRF或者XXE上做的很不错,你们可以看看他的演讲内容和博客。
最喜欢的演讲之一: 《Nicolas Grégoire – Hunting for Top Bounties》
最喜欢的博文之一: 《Compromising an unreachable Solr server with CVE-2013-6397》
我写这篇博文是因为刚提交了一份Mubix的 CFDB 的 SSRF漏洞 ,这里有些其中的细节。在关于CFDB的发现里,我加入了一些以前工作的内容链接和某些有用的资源。
鄙人认为CFDB是一个伟大的项目,它在我们这行有着重大意义,急需我们做出贡献。
最终的想法
与客户端漏洞XSS和CSRF不同,SSRF可以访问后端不可直达的基础设施。如果你找到了这类漏洞,记得要去证明它的风险。
欢迎对本文指出批评,读者的反馈和鼓励是我最大的荣幸。
*参考来源: sethsec ,FB小编dawner编译,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)