基于Hessian2反序列化挖掘Spring原生利用链
字数 1760 2025-08-29 22:41:10
基于Hessian2反序列化挖掘Spring原生利用链技术分析
0x00 漏洞背景与准备
漏洞环境要求
- Hessian版本:最新4.0.66版本(当前版本通杀)
- Spring-context版本:
- <6.0.0版本可直接利用
- ≥6.0.0版本需要额外绕过手法
- JDK限制:不严格,可通过绕过方法突破
核心漏洞点
漏洞位于SimpleJndiBeanFactory类的getBean(String name)方法,该方法会触发JNDI注入。
0x01 漏洞分析
1. 初始漏洞点分析
SimpleJndiBeanFactory.getBean()方法:
- 接受一个参数
name(可设置为恶意JNDI服务端地址) - 默认会调用同类的
lookup方法 lookup方法会触发JNDI请求
关键限制:
SimpleJndiBeanFactory类未实现Serializable接口- 无法直接用于Java原生反序列化
- 但Hessian2反序列化不要求实现该接口
2. 调用链构造过程
第一步:寻找getBean调用点
发现TargetBeanObjectFactory类的getObject()方法:
- 可调用
SimpleJndiBeanFactory.getBean() - 需要设置两个成员:
beanFactory:设置为SimpleJndiBeanFactory实例targetBeanName:设置为JNDI服务端地址
构造方法:
通过ObjectFactoryCreatingFactoryBean.createInstance()方法构造TargetBeanObjectFactory类并赋值成员。
第二步:寻找突破口
发现ObjectFactoryDelegatingInvocationHandler类:
- 实现了
InvocationHandler接口 - 可被封装到动态代理类
- 当代理类触发任意方法(除
equals()、hashCode()、toString()外)时,会调用invoke方法
invoke方法关键逻辑:
- 满足条件时会触发
ObjectFactory.getObject()方法 - 可将
objectFactory成员设置为上一步构造的TargetBeanObjectFactory
第三步:寻找触发点
选择TreeMap作为触发点:
TreeMap.put()会调用k1.compareTo(k2)- 如果
k1是恶意动态代理类,会触发ObjectFactoryDelegatingInvocationHandler.invoke() - 从而形成完整调用链
0x02 完整利用链构造
利用链流程
Hessian2反序列化 → TreeMap.put() → 动态代理.compareTo() →
ObjectFactoryDelegatingInvocationHandler.invoke() →
TargetBeanObjectFactory.getObject() →
SimpleJndiBeanFactory.getBean() → JNDI注入
POC关键代码结构
- 构造恶意
SimpleJndiBeanFactory实例 - 通过
ObjectFactoryCreatingFactoryBean构造TargetBeanObjectFactory - 创建
ObjectFactoryDelegatingInvocationHandler并设置objectFactory - 创建动态代理对象
- 将代理对象作为key放入
TreeMap - 序列化
TreeMap并通过Hessian2发送
0x03 防御与修复建议
修复方案
- 升级Spring-context到6.0.0及以上版本
- 对Hessian2反序列化进行白名单限制
- 禁用不必要的JNDI服务
- 设置
com.sun.jndi.rmi.object.trustURLCodebase为false
检测方法
- 监控异常JNDI请求
- 检查Hessian2反序列化过程中的异常TreeMap操作
- 关注动态代理类的创建和使用
0x04 扩展思考
可能的变种利用
- 尝试其他触发点替代
TreeMap - 探索其他实现了
InvocationHandler的类 - 结合其他Spring组件的反序列化特性
相关技术延伸
- Hessian2反序列化特性研究
- Spring框架动态代理机制
- JNDI注入的多种利用方式
附录:参考链接
- 原文链接
- Java Chains工具使用
- Hessian2官方文档
- Spring安全公告