关于Hessian2二次反序列化中我学到了几点
字数 2184 2025-08-29 08:31:54

Hessian2二次反序列化与Rome链利用技术详解

前言

本文深入分析Hessian2通过Rome链进行两次反序列化完成恶意EvilTemplatesImpl注入的技术细节。重点探讨TemplatesImpl的触发机制、Hessian2反序列化特性以及SignedObject在绕过限制中的作用。

1. TemplatesImpl触发机制详解

TemplatesImpl是Java XML处理中的一个关键类,其触发机制涉及以下关键方法:

1.1 方法调用链

  1. getOutputProperties()

    • 这是触发链的入口点
    • 会调用newTransformer()方法
  2. newTransformer()

    • 调用getTransletInstance()来创建恶意类
    • 是实际触发恶意代码执行的关键环节
  3. getTransletInstance()

    • 会进入defineTransletClasses()方法
    • 需要满足两个条件才能进入defineTransletClasses:
      • _name不能为空
      • _class必须为空

1.2 defineTransletClasses关键点

在defineTransletClasses方法中,有几个需要特别注意的点:

  1. _tfactory属性

    • 这是需要特别关注的关键属性
    • 它是为何需要调用二次反序列化的关键原因
    • 在第一次反序列化时可能为空,导致NullPointerException
  2. 类定义过程

    • 负责加载和定义恶意类
    • 需要正确的字节码和类名设置

2. Hessian2反序列化特性

2.1 序列化限制

Hessian2对序列化有以下重要限制:

  1. transient字段处理

    • Hessian2Input与Hessian2Output均不能对transient修饰的成员进行序列化或反序列化
    • 这是与Java原生序列化的重要区别
  2. ObjectInput/ObjectOutput行为

    • 除非相关类重写了readObject或writeObject方法
    • 否则也无法操作transient修饰的成员变量

2.2 TemplatesImpl的特殊处理

TemplatesImpl类有以下特殊行为:

  1. _tfactory属性

    • 虽然是transient修饰
    • 但重写了readObject方法,会在其中生成_tfactory的实例
    • 这是解决NullPointerException的关键
  2. 二次反序列化的必要性

    • 第一次反序列化时_tfactory可能为空
    • 通过重写的readObject方法可以正确初始化_tfactory
    • 使得后续的getOutputProperties调用不会抛出异常

3. SignedObject的利用

3.1 SignedObject特性

SignedObject在sofastack/sofa-hessian的黑名单中被发现,具有以下特点:

  1. 序列化机制

    • 使用ObjectInput.readObject和ObjectOutput.writeObject操作Serializable类
    • 字节码存储在this.content属性中
  2. 反序列化触发

    • 可以通过getObject函数触发反序列化
    • 因为是getter方法,可以在ToStringBean的toString方法中被调用

3.2 解决_tfactory为空的问题

SignedObject可以用于解决TemplatesImpl中_tfactory为空的问题:

  1. 封装机制

    • 将TemplatesImpl封装在SignedObject中
    • 通过getObject触发完整的反序列化过程
  2. 示例代码

public static void main(String[] args) throws Exception {
    // 创建恶意TemplatesImpl对象
    TemplatesImpl templates = createMaliciousTemplates();
    
    // 创建SignedObject封装
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
    keyPairGenerator.initialize(1024);
    KeyPair keyPair = keyPairGenerator.genKeyPair();
    PrivateKey privateKey = keyPair.getPrivate();
    Signature signature = Signature.getInstance(privateKey.getAlgorithm());
    
    SignedObject signedObject = new SignedObject(templates, privateKey, signature);
    
    // 触发反序列化
    TemplatesImpl evil = (TemplatesImpl) signedObject.getObject();
}

3.3 完整利用链

  1. 第一次反序列化

    • Hessian2反序列化SignedObject
    • 此时TemplatesImpl的_tfactory可能未正确初始化
  2. 第二次反序列化

    • 通过getObject触发完整反序列化
    • TemplatesImpl的readObject被调用,正确初始化_tfactory
    • 后续调用getOutputProperties不会抛出异常

4. 完整攻击流程

  1. 构造恶意TemplatesImpl

    • 设置_name不为空
    • 确保_class为空
    • 包含恶意字节码
  2. 封装到SignedObject

    • 利用SignedObject封装恶意对象
    • 准备触发二次反序列化
  3. Hessian2序列化

    • 将SignedObject序列化为Hessian2格式
    • 准备发送给目标
  4. 目标反序列化

    • 目标使用Hessian2反序列化
    • 触发SignedObject的getObject
    • 完成TemplatesImpl的完整反序列化
    • 通过Rome链触发恶意代码执行

5. 防御建议

  1. 黑名单机制

    • 将SignedObject加入反序列化黑名单
    • 限制危险类的反序列化
  2. 输入验证

    • 严格验证反序列化的数据来源
    • 避免不可信数据的反序列化
  3. 安全配置

    • 使用最新版本的序列化库
    • 应用安全补丁

6. 参考资源

  1. CommonsCollections3分析 - 笑花大王
  2. Java"后反序列化漏洞"利用思路 - Ruilin
  3. Gadget1.java - Ruilin
  4. Hessian 反序列化漏洞分析 - D4ck

通过深入理解这些技术细节,安全研究人员可以更好地防御这类攻击,同时也能够更有效地进行安全测试和漏洞挖掘。

Hessian2二次反序列化与Rome链利用技术详解 前言 本文深入分析Hessian2通过Rome链进行两次反序列化完成恶意EvilTemplatesImpl注入的技术细节。重点探讨TemplatesImpl的触发机制、Hessian2反序列化特性以及SignedObject在绕过限制中的作用。 1. TemplatesImpl触发机制详解 TemplatesImpl是Java XML处理中的一个关键类,其触发机制涉及以下关键方法: 1.1 方法调用链 getOutputProperties() 这是触发链的入口点 会调用newTransformer()方法 newTransformer() 调用getTransletInstance()来创建恶意类 是实际触发恶意代码执行的关键环节 getTransletInstance() 会进入defineTransletClasses()方法 需要满足两个条件才能进入defineTransletClasses: _name 不能为空 _class 必须为空 1.2 defineTransletClasses关键点 在defineTransletClasses方法中,有几个需要特别注意的点: _ tfactory属性 这是需要特别关注的关键属性 它是为何需要调用二次反序列化的关键原因 在第一次反序列化时可能为空,导致NullPointerException 类定义过程 负责加载和定义恶意类 需要正确的字节码和类名设置 2. Hessian2反序列化特性 2.1 序列化限制 Hessian2对序列化有以下重要限制: transient字段处理 Hessian2Input与Hessian2Output均不能对transient修饰的成员进行序列化或反序列化 这是与Java原生序列化的重要区别 ObjectInput/ObjectOutput行为 除非相关类重写了readObject或writeObject方法 否则也无法操作transient修饰的成员变量 2.2 TemplatesImpl的特殊处理 TemplatesImpl类有以下特殊行为: _ tfactory属性 虽然是transient修饰 但重写了readObject方法,会在其中生成_ tfactory的实例 这是解决NullPointerException的关键 二次反序列化的必要性 第一次反序列化时_ tfactory可能为空 通过重写的readObject方法可以正确初始化_ tfactory 使得后续的getOutputProperties调用不会抛出异常 3. SignedObject的利用 3.1 SignedObject特性 SignedObject在sofastack/sofa-hessian的黑名单中被发现,具有以下特点: 序列化机制 使用ObjectInput.readObject和ObjectOutput.writeObject操作Serializable类 字节码存储在this.content属性中 反序列化触发 可以通过getObject函数触发反序列化 因为是getter方法,可以在ToStringBean的toString方法中被调用 3.2 解决_ tfactory为空的问题 SignedObject可以用于解决TemplatesImpl中_ tfactory为空的问题: 封装机制 将TemplatesImpl封装在SignedObject中 通过getObject触发完整的反序列化过程 示例代码 3.3 完整利用链 第一次反序列化 Hessian2反序列化SignedObject 此时TemplatesImpl的_ tfactory可能未正确初始化 第二次反序列化 通过getObject触发完整反序列化 TemplatesImpl的readObject被调用,正确初始化_ tfactory 后续调用getOutputProperties不会抛出异常 4. 完整攻击流程 构造恶意TemplatesImpl 设置_ name不为空 确保_ class为空 包含恶意字节码 封装到SignedObject 利用SignedObject封装恶意对象 准备触发二次反序列化 Hessian2序列化 将SignedObject序列化为Hessian2格式 准备发送给目标 目标反序列化 目标使用Hessian2反序列化 触发SignedObject的getObject 完成TemplatesImpl的完整反序列化 通过Rome链触发恶意代码执行 5. 防御建议 黑名单机制 将SignedObject加入反序列化黑名单 限制危险类的反序列化 输入验证 严格验证反序列化的数据来源 避免不可信数据的反序列化 安全配置 使用最新版本的序列化库 应用安全补丁 6. 参考资源 CommonsCollections3分析 - 笑花大王 Java"后反序列化漏洞"利用思路 - Ruilin Gadget1.java - Ruilin Hessian 反序列化漏洞分析 - D4ck 通过深入理解这些技术细节,安全研究人员可以更好地防御这类攻击,同时也能够更有效地进行安全测试和漏洞挖掘。