XStream CVE-2021-21341拒绝服务漏洞漏洞分析
字数 1951 2025-08-09 16:00:17

XStream CVE-2021-21341拒绝服务漏洞深度分析

1. 漏洞概述

CVE-2021-21341是XStream在2021年爆出的一个拒绝服务(DoS)漏洞。XStream是一个常用的Java对象和XML相互转换的工具。与常见的命令执行漏洞、JNDI注入漏洞不同,这个拒绝服务漏洞是代码逻辑上的漏洞,利用链构造十分巧妙。

2. 漏洞原理

2.1 利用链分析

该漏洞的利用链前半部分与CVE-2020-26217相同,都是利用Base64Data.get方法替换一个恶意的InputStream。区别在于之前的入口被封堵了,因此使用了PriorityQueue+ObservableList$1的方法调用到Base64DatatoString方法。

完整利用链如下:

PriorityQueue.readObject()
PriorityQueue.heapify()
PriorityQueue.siftDown()
PriorityQueue.siftDownUsingCompartor
javaFx.collections.ObservableList$1
com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data.toString
com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data.get
com.sun.xml.internal.bind.v2.util.ByteArrayOutputStreamEx.readFrom
while (True) ...

2.2 核心漏洞点

漏洞的核心在于ByteArrayOutputStreamExreadFrom()方法中的无限循环:

public void readFrom(InputStream is) throws IOException {
    while(true) {
        if(this.count == this.buf.length) {
            byte[] data = new byte[this.buf.length * 2];
            System.arraycopy(this.buf, 0, data, 0, this.buf.length);
            this.buf = data;
        }
        int sz = is.read(this.buf, this.count, this.buf.length - this.count);
        if(sz < 0) {
            return;
        }
        this.count += sz;
    }
}

read函数中,会计算count-pos值。如果将pos设置为Integer.MIN_VALUEcount设置为0,那么count-pos会等于pos(由于整数溢出)。这将导致readFrom方法陷入无限循环,从而造成拒绝服务。

3. 利用链构造详解

3.1 利用链组件

  1. Source: PriorityQueue.readObject()

    • XStream会调用PriorityQueuereadObject方法
  2. Gadget: ObservableList$1比较器

    • 这是一个匿名比较器类,位于javafx.collections.ObservableList
    • 类名为javafx.collections.ObservableList$1
    • 该比较器会调用比较对象的toString方法
  3. Sink: ByteArrayOutputStreamEx.readFrom()

    • 通过Base64Data.toString()Base64Data.get()ByteArrayOutputStreamEx.readFrom()
    • 其中的无限循环导致拒绝服务

3.2 POC构造方法

  1. 确定利用链
  2. 构造对应的对象
  3. 调用XStream的toXML方法生成恶意XML文本

关键实现细节:

  1. 获取匿名比较器类:

    Class<?> comparatorClass = Class.forName("javafx.collections.ObservableList$1");
    
  2. 实例化比较器:

    • 使用Unsafe.allocateInstance方法直接实例化对象,绕过构造函数
  3. 设置PriorityQueue:

    • 创建一个PriorityQueue实例
    • 设置比较器为上面实例化的匿名比较器
    • 添加包含恶意Base64Data的对象到队列中

4. 技术细节分析

4.1 整数溢出原理

Java中int类型的范围是-2,147,483,648到2,147,483,647。当计算0 - Integer.MIN_VALUE时:

  1. Integer.MIN_VALUE的二进制表示:10000000000000000000000000000000
  2. 取反加一后仍然是10000000000000000000000000000000
  3. 因此0 - Integer.MIN_VALUE的结果仍然是Integer.MIN_VALUE

这导致readFrom方法中的is.read()调用时传入的len参数为负数,但被转换为大正数,从而陷入无限循环。

4.2 XStream反序列化特点

XStream的一个重要特点是它可以利用没有实现Serializable接口的类进行反序列化操作,这大大扩展了可利用的类范围。

5. 影响范围

  • 受影响版本:XStream 1.4.15及之前版本
  • 需要较高版本的JDK(包含javafx.collections.ObservableList类)

6. 修复方案

XStream官方在后续版本中修复了此漏洞,建议用户升级到最新版本。修复措施包括:

  1. 限制某些危险类的反序列化
  2. 对可能导致无限循环的输入进行校验
  3. 改进Base64Data类的处理逻辑

7. 防御建议

  1. 及时升级XStream到最新版本
  2. 实施输入验证,过滤恶意XML输入
  3. 使用XStream的安全框架配置,限制可反序列化的类
  4. 在关键服务中实施资源限制,防止拒绝服务攻击

8. 总结

CVE-2021-21341展示了XStream在处理特定对象图时的逻辑缺陷,通过精心构造的利用链,攻击者可以触发无限循环导致拒绝服务。这个漏洞的利用链构造巧妙,结合了多个组件的特性,包括集合类、比较器和数据流处理类,最终通过整数溢出实现攻击效果。

XStream CVE-2021-21341拒绝服务漏洞深度分析 1. 漏洞概述 CVE-2021-21341是XStream在2021年爆出的一个拒绝服务(DoS)漏洞。XStream是一个常用的Java对象和XML相互转换的工具。与常见的命令执行漏洞、JNDI注入漏洞不同,这个拒绝服务漏洞是代码逻辑上的漏洞,利用链构造十分巧妙。 2. 漏洞原理 2.1 利用链分析 该漏洞的利用链前半部分与CVE-2020-26217相同,都是利用 Base64Data.get 方法替换一个恶意的 InputStream 。区别在于之前的入口被封堵了,因此使用了 PriorityQueue + ObservableList$1 的方法调用到 Base64Data 的 toString 方法。 完整利用链如下: 2.2 核心漏洞点 漏洞的核心在于 ByteArrayOutputStreamEx 的 readFrom() 方法中的无限循环: 在 read 函数中,会计算 count-pos 值。如果将 pos 设置为 Integer.MIN_VALUE , count 设置为0,那么 count-pos 会等于 pos (由于整数溢出)。这将导致 readFrom 方法陷入无限循环,从而造成拒绝服务。 3. 利用链构造详解 3.1 利用链组件 Source : PriorityQueue.readObject() XStream会调用 PriorityQueue 的 readObject 方法 Gadget : ObservableList$1 比较器 这是一个匿名比较器类,位于 javafx.collections.ObservableList 中 类名为 javafx.collections.ObservableList$1 该比较器会调用比较对象的 toString 方法 Sink : ByteArrayOutputStreamEx.readFrom() 通过 Base64Data.toString() → Base64Data.get() → ByteArrayOutputStreamEx.readFrom() 其中的无限循环导致拒绝服务 3.2 POC构造方法 确定利用链 构造对应的对象 调用XStream的 toXML 方法生成恶意XML文本 关键实现细节: 获取匿名比较器类 : 实例化比较器 : 使用 Unsafe.allocateInstance 方法直接实例化对象,绕过构造函数 设置PriorityQueue : 创建一个 PriorityQueue 实例 设置比较器为上面实例化的匿名比较器 添加包含恶意 Base64Data 的对象到队列中 4. 技术细节分析 4.1 整数溢出原理 Java中 int 类型的范围是-2,147,483,648到2,147,483,647。当计算 0 - Integer.MIN_VALUE 时: Integer.MIN_VALUE 的二进制表示: 10000000000000000000000000000000 取反加一后仍然是 10000000000000000000000000000000 因此 0 - Integer.MIN_VALUE 的结果仍然是 Integer.MIN_VALUE 这导致 readFrom 方法中的 is.read() 调用时传入的 len 参数为负数,但被转换为大正数,从而陷入无限循环。 4.2 XStream反序列化特点 XStream的一个重要特点是它可以利用没有实现 Serializable 接口的类进行反序列化操作,这大大扩展了可利用的类范围。 5. 影响范围 受影响版本:XStream 1.4.15及之前版本 需要较高版本的JDK(包含 javafx.collections.ObservableList 类) 6. 修复方案 XStream官方在后续版本中修复了此漏洞,建议用户升级到最新版本。修复措施包括: 限制某些危险类的反序列化 对可能导致无限循环的输入进行校验 改进 Base64Data 类的处理逻辑 7. 防御建议 及时升级XStream到最新版本 实施输入验证,过滤恶意XML输入 使用XStream的安全框架配置,限制可反序列化的类 在关键服务中实施资源限制,防止拒绝服务攻击 8. 总结 CVE-2021-21341展示了XStream在处理特定对象图时的逻辑缺陷,通过精心构造的利用链,攻击者可以触发无限循环导致拒绝服务。这个漏洞的利用链构造巧妙,结合了多个组件的特性,包括集合类、比较器和数据流处理类,最终通过整数溢出实现攻击效果。