基于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关键代码结构

  1. 构造恶意SimpleJndiBeanFactory实例
  2. 通过ObjectFactoryCreatingFactoryBean构造TargetBeanObjectFactory
  3. 创建ObjectFactoryDelegatingInvocationHandler并设置objectFactory
  4. 创建动态代理对象
  5. 将代理对象作为key放入TreeMap
  6. 序列化TreeMap并通过Hessian2发送

0x03 防御与修复建议

修复方案

  1. 升级Spring-context到6.0.0及以上版本
  2. 对Hessian2反序列化进行白名单限制
  3. 禁用不必要的JNDI服务
  4. 设置com.sun.jndi.rmi.object.trustURLCodebase为false

检测方法

  1. 监控异常JNDI请求
  2. 检查Hessian2反序列化过程中的异常TreeMap操作
  3. 关注动态代理类的创建和使用

0x04 扩展思考

可能的变种利用

  1. 尝试其他触发点替代TreeMap
  2. 探索其他实现了InvocationHandler的类
  3. 结合其他Spring组件的反序列化特性

相关技术延伸

  1. Hessian2反序列化特性研究
  2. Spring框架动态代理机制
  3. JNDI注入的多种利用方式

附录:参考链接

  • 原文链接
  • Java Chains工具使用
  • Hessian2官方文档
  • Spring安全公告
基于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 完整利用链构造 利用链流程 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安全公告