Dubbo漏洞 - 13 CVE-2021-43297

CVE-2021-43297 — Hessian 异常处理 toString RCE

漏洞概述

CVE 编号:CVE-2021-43297

CVSS 评分:8.6(High)

影响版本:Dubbo 2.6.x < 2.6.12, 2.7.x < 2.7.15, 3.0.x < 3.0.5

修复版本:2.6.12, 2.7.15, 3.0.5

攻击协议:Dubbo 协议

攻击方式:利用 Hessian2 异常处理中的 toString 调用

漏洞原理

背景

经过多轮修复,Hessian2 的正常反序列化路径已经有了黑白名单保护

hashCode()equals()compareTo() 触发的 gadget chain 被拦截

toString() 触发的链被忽略了

根因

当 Hessian2 反序列化过程中遇到异常(如类型不匹配、格式错误)

异常处理代码会尝试记录日志,调用对象的 toString() 方法获取信息

如果此时对象已经被部分反序列化,且包含 gadget chain

toString() 调用就会触发链执行

调用链

1
2
3
4
5
6
7
8
9
10
11
12
攻击者发送畸形 Hessian2 数据
→ Hessian2Input.readObject()
→ 开始反序列化 → 创建对象并设置部分字段
→ 遇到故意构造的异常(如类型不匹配)
→ catch (Exception e) {
log.error("Decode error: " + obj.toString());
// ↑ toString 触发!
}
→ ToStringBean.toString() (ROME 链)
→ 遍历 getter 方法
→ TemplatesImpl.getOutputProperties()
→ 加载恶意字节码 → RCE

精巧之处

攻击者需要故意构造格式错误的 Hessian2 数据

数据前半部分能正常反序列化(创建 gadget chain 对象)

后半部分故意出错(触发异常)

异常处理调用 toString() → 触发已经构造好的 gadget chain

复现难度

比前几个 CVE 复杂,需要精确控制 Hessian2 数据的解析流程

需要理解 Hessian2 的二进制格式和解析器状态机

已有工具(dubbo-exp 的新版本)支持此漏洞的利用

复现步骤

环境搭建

1
2
cd environments/cve-2021-43297
docker-compose up -d

攻击思路

  1. 构造包含 ROME ToStringBean 的 Hessian2 数据

  2. 在数据末尾插入错误的类型标记

  3. 发送到 Dubbo Provider

  4. 解析器正常处理前半部分,在后半部分抛异常

  5. 异常处理调用 toString → RCE

补丁分析

修复方式

异常处理中不再调用对象的 toString() 方法

改为安全的日志记录方式(只记录类名和异常信息)

修复代码

1
2
3
4
5
6
7
8
9
10
// 修复前
catch (Exception e) {
log.error("Failed to decode: " + obj.toString(), e); // 危险
}

// 修复后
catch (Exception e) {
log.error("Failed to decode object of type: " +
(obj != null ? obj.getClass().getName() : "null"), e); // 安全
}

思考与延伸

异常处理代码也是攻击面

开发者在异常处理中经常调用 toString() 打日志,这可能成为漏洞

安全审计时应该关注:异常处理路径中是否有对不受信数据调用 toString()/hashCode()/equals()

隐蔽性:攻击利用的是异常路径,不是正常业务路径,更难被监控发现


上一章 目录 下一章
12-CVE-2021-32824 Dubbo漏洞 14-CVE-2023-23638