XMLDecoder反序列化漏洞分析

0x00 前言

XmlDeocoder是java自带的以SAX方式解析xml的类。其在反序列化经过特殊构造的数据时可执行任意命令。Weblogic中就因为默认包含的wls-wastwls9_async_response war_async等包中采用xmldecoder处理XML数据,出现了多次具有严重影响的反序列化漏洞:CVE-2017-3506 -> CVE-2017-10271(10352) -> CVE-2019-2725 -> CVE-2019-2729

下面是在学习XmlDecoder反序列化漏洞过程中的一点学习记录。本次分析使用JDK版本为1.7.0_80

0x01 Xmldecoder反序列化过程

1
2
3
4
5
6
7
8
9
10
11
12
//XmlTest.java
import java.io.*;
import java.beans.XMLDecoder;

public class XmlTest {
public static void main(String[] args) throws FileNotFoundException {
String filename = "1.xml";
XMLDecoder XD =new XMLDecoder(new FileInputStream(filename));
Object o = XD.readObject();
XD.close();
}
}

使用上面的代码进行本次的动态跟踪xmldecoder反序列化流程

1.xml中的内容为经过特殊构造的xml数据,效果为弹出计算器

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<object class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="1">
<void index="0">
<string>calc</string>
</void>
</array>
<void method="start"/>
</object>

java.lang.ProcessBuilder类的start方法处下断点,可以看到calc命令被传入执行,并且函数调用栈非常深。

下面在readObject处下断点,开始对整个过程动态追踪。

XMLDecoder的解析过程是基于Java自带的SAX XML解析进行的。所有类都在com.sun.beans.decoder包中。

前面的调用栈有点深,这里不做详细记录了,直接跳到DocumentHandler类的startElement方法处跟踪对标签的解析。

DocumentHandler的构造函数中,针对不同的标签,对应类不同的ElementHandler进行处理

首先解析object标签,创建ObjectElementHandler,设置Owner和Parent

跟进addAttribute方法进行属性设置,由于该方式没有对class属性做处理,因此会调用ObjectElementHandler父类的方法,即NewElementHandler类的addAttribute方法。

在该方法中进入对class属性的处理,设置type值为java.lang.ProcessBuilder对应的对象

设置完属性值后,调用startElement方法,这里不满足条件,直接退出。

然后开始解析array标签,创建ArrayElementHandler,设置Owner和Parent

同样调用addAttribute方法进行属性设置,这里继续调用了ArrayElementHandler父类NewElementHandleraddAttribute方法

设置type为java.lang.String类对应的对象

继续设置array的length属性后,最后进入到startElement方法,这里array具有length属性,继续调用getValueObject方法

因为ArrayElementHandler没有getValueObject()方法,所以调用其父类NewElementHandler的方法

在父类方法中,又调用本类的有参getValueObject方法,在该方法中创建了值为String类型长度为length的数组并返回

然后开始处理void标签,创建VoidElementHandler,设置Owner和Parent

然后调用VoidElementHandler父类ObjectElementHandleraddAttribute方法设置index属性

继续解析string标签,创建对应StringElementHandler,设置Owner和Parent。因为继承关系,会调用父类ElementHandlerstartElement(),其为空方法,直接返回。

接着解析到string的闭合标签,开始endElement。调用父类的endElement()方法。

调用本类getValueObject方法

设置value值为string标签内的内容calc

然后闭合void标签

然后闭合array标签,接着继续解析下面的void标签

调用其父类addAttribute方法设置method属性为start

随后调用endElement方法闭合void标签,调用其父类的无参getValueObject方法

在父类getValueObject()方法中调用本类有参getValueObject方法

在本类方法中又调用了getContextBean(注意此处,下面的调用链将为此处v3返回值)

继续跟进,会调用父类ElementHandler的getContexBean方法

然后会调用parent.getValueObjectObjectElementHandlergetValueObject方法

ObjectElementHandler没有无参getValueObject()方法,会调用其父类方法。然后又调用类其有参getValueObject方法,并将返回值赋给value.

继续跟进,会调用getContextBean方法

lNUQfK.png

然后返回type值即为之前设置的java.lang.ProcessBuilder对应的对象

lNUr6g.png

最终将这个java.lang.ProcessBuilder对应的对象赋值到上面提到的v3

lNdjyD.png

之后v4会设置为this.method,即为start

lNwemQ.png

之后调用创建一个Expresstion对象,并调用其getValue方法,此方法会在此目标上动态查找具有指定 methodName 的方法,并调用该方法。详情参加Expression。即调用java.lang.ProcessBuilder的start方法,执行命令,弹出计算器。

lN0kNR.png

0x02 其他利用标签

从上面的继承关系可以看到,VoidElementHandler继承自ObjectElementHandler,且仅改写了isArgument()方法,因此对整个触发过程中并无影响,所以此处使用void标签与object标签效果相同。

因此还可以使用下面的利用方式

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="1">
<void index="0">
<string>calc</string>
</void>
</array>
<void method="start"/>
</void>

0x03 后记

篇幅有点长了,这个漏洞也从2019年学到了2020年,菜鸡的java入门之路属实有点难。

后面将再起文章,分析weblogic xmldecoder的反序列化漏洞。

0x04 参考资料

http://jszx-jxpt.cuit.edu.cn/JavaAPI/java/beans/Expression.html

https://blog.csdn.net/fnmsd/article/details/89889144

本文标题:XMLDecoder反序列化漏洞分析

文章作者:boogle

发布时间:2020年01月02日 - 23:16

最后更新:2020年01月04日 - 15:38

原始链接:https://zhengbao.wang/XMLDecoder反序列化漏洞分析/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

感觉写的不错,给买个棒棒糖呗