Java远程方法调用RMI利用分析
字数 2083 2025-08-15 21:32:20

Java RMI 安全漏洞分析与利用教学文档

1. 基础概念

1.1 JNDI (Java命名和目录接口)

  • 提供统一的客户端API,通过不同的访问提供者接口(JNDI SPI)实现
  • 将JNDI API映射为特定的命名服务和目录系统
  • 使Java应用程序能与命名服务和目录服务交互

1.2 JRMP (Java远程方法协议)

  • Java特有的协议,用于查找和引用远程对象
  • 运行在Java RMI之下,TCP/IP之上的线路层协议

1.3 RMI (远程方法调用)

  • Java实现远程过程调用的API
  • 使客户端程序能调用远程服务器上的对象
  • 宗旨是尽可能简化远程接口对象的使用

2. RMI攻击向量

2.1 序列化攻击

  • 无版本限制,但部分逻辑会因版本不同而有差异
  • 关键版本影响:6u45、7u21修改默认安全设置

2.2 两种bind区别

  1. Server ↔ RMI Registry ↔ Client

    • bind注册时进行序列化传输服务名&Ref
    • 进入RegistryImpl_Skel.dispatch反序列化获取
  2. Server(RMI Registry) ↔ Client

    • 同一台机器,bind时已有Ref,无需序列化传输
    • 只需在bindings list中添加键值

3. 注册与请求流程分析

3.1 bind流程

  1. ServiceImpl继承UnicastRemoteObject,实例化时通过exportObject创建stub
  2. 通过bind向RMI Registry注册服务名&stub
  3. RegistryImpl_Stub#bind中两次writeObject写入序列化的服务名&stub
  4. RMI Registry通过反序列化获取服务名&stub,写入bindings List

攻击点:Server通过bind操作对RMI Registry进行序列化攻击

3.2 lookup流程

  1. Client向RMI Registry发送lookup请求(操作数为2)
  2. RMI Registry反序列化获取查询服务名
  3. 从bindings list中查询,通过writeObject将stub序列化传输给Client
  4. Client通过readObject接收

攻击点

  1. Client通过lookup操作对RMI Registry进行序列化攻击
  2. RMI Registry通过lookup操作被动攻击Client

3.3 远程调用机制

  • 由RemoteObjectInvocationHandler实现动态代理
  • 最终由UnicastRef#invoke实现调用
  • marshalValue打包参数,unmarshalValue对返回内容反序列化

4. 攻击方向总结

  1. 向RMI Registry申请bind操作进行序列化攻击
  2. 向RMI Registry申请lookup操作进行序列化攻击
  3. RMI Registry通过lookup操作被动式序列化攻击请求者

5. 具体攻击技术

5.1 bind攻击(RMIRegistryExploit)

  • 利用动态代理Remote.class
  • 通过AnnotationInvocationHandler触发反序列化
  • 需要java.rmi.server.useCodebaseOnly=false(6u45、7u21前默认)

5.2 RMI动态类加载机制

  • 本地CLASSPATH找不到类时,从指定codebase加载class
  • 防御:6u45、7u21后useCodebaseOnly默认为true

5.3 Client攻击Server

  • Server加载远程类时触发
  • 需要配置RMISecurityManager且useCodebaseOnly=false

5.4 Server攻击Client

  • Client获取结果后需要获取远程类进行本地反序列化

5.5 JRMP攻击

  • 直接利用socket通信,不接收服务端返回更安全
  • 相关工具:
    • payloads.JRMPListener:开启JRMP监听
    • payloads.JRMPClient:发送注册Ref
    • exploit.JRMPListener:被动传输序列化payload
    • exploit.JRMPClient:主动传输序列化payload

6. DGC(分布式垃圾回收)

  • 跟踪远程对象在客户机中的使用
  • 当引用过期且未更新时,服务器将垃圾回收远程对象

7. JNDI Reference攻击

  • Client执行lookup时加载远程恶意类实现RCE
  • 防御:
    • 6u141、7u131、8u121起默认trustURLCodebase=false
    • JEP290对可反序列化类做白名单检测

8. 防御措施

  1. 升级JDK到安全版本
  2. 设置java.rmi.server.useCodebaseOnly=true
  3. 设置com.sun.jndi.rmi.object.trustURLCodebase=false
  4. 启用JEP290反序列化过滤机制

9. 攻击演示命令示例

  1. bind攻击:
java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit <rmi_ip> <rmi_port> <payload> <args>
  1. JRMP监听:
java -cp ysoserial.jar ysoserial.exploit.JRMPListener <port> <payload> <args>
  1. JRMP客户端攻击:
java -cp ysoserial.jar ysoserial.exploit.JRMPClient <target_ip> <target_port> <payload> <args>
Java RMI 安全漏洞分析与利用教学文档 1. 基础概念 1.1 JNDI (Java命名和目录接口) 提供统一的客户端API,通过不同的访问提供者接口(JNDI SPI)实现 将JNDI API映射为特定的命名服务和目录系统 使Java应用程序能与命名服务和目录服务交互 1.2 JRMP (Java远程方法协议) Java特有的协议,用于查找和引用远程对象 运行在Java RMI之下,TCP/IP之上的线路层协议 1.3 RMI (远程方法调用) Java实现远程过程调用的API 使客户端程序能调用远程服务器上的对象 宗旨是尽可能简化远程接口对象的使用 2. RMI攻击向量 2.1 序列化攻击 无版本限制,但部分逻辑会因版本不同而有差异 关键版本影响:6u45、7u21修改默认安全设置 2.2 两种bind区别 Server ↔ RMI Registry ↔ Client bind注册时进行序列化传输服务名&Ref 进入RegistryImpl_ Skel.dispatch反序列化获取 Server(RMI Registry) ↔ Client 同一台机器,bind时已有Ref,无需序列化传输 只需在bindings list中添加键值 3. 注册与请求流程分析 3.1 bind流程 ServiceImpl继承UnicastRemoteObject,实例化时通过exportObject创建stub 通过bind向RMI Registry注册服务名&stub RegistryImpl_ Stub#bind中两次writeObject写入序列化的服务名&stub RMI Registry通过反序列化获取服务名&stub,写入bindings List 攻击点 :Server通过bind操作对RMI Registry进行序列化攻击 3.2 lookup流程 Client向RMI Registry发送lookup请求(操作数为2) RMI Registry反序列化获取查询服务名 从bindings list中查询,通过writeObject将stub序列化传输给Client Client通过readObject接收 攻击点 : Client通过lookup操作对RMI Registry进行序列化攻击 RMI Registry通过lookup操作被动攻击Client 3.3 远程调用机制 由RemoteObjectInvocationHandler实现动态代理 最终由UnicastRef#invoke实现调用 marshalValue打包参数,unmarshalValue对返回内容反序列化 4. 攻击方向总结 向RMI Registry申请bind操作进行序列化攻击 向RMI Registry申请lookup操作进行序列化攻击 RMI Registry通过lookup操作被动式序列化攻击请求者 5. 具体攻击技术 5.1 bind攻击(RMIRegistryExploit) 利用动态代理Remote.class 通过AnnotationInvocationHandler触发反序列化 需要java.rmi.server.useCodebaseOnly=false(6u45、7u21前默认) 5.2 RMI动态类加载机制 本地CLASSPATH找不到类时,从指定codebase加载class 防御:6u45、7u21后useCodebaseOnly默认为true 5.3 Client攻击Server Server加载远程类时触发 需要配置RMISecurityManager且useCodebaseOnly=false 5.4 Server攻击Client Client获取结果后需要获取远程类进行本地反序列化 5.5 JRMP攻击 直接利用socket通信,不接收服务端返回更安全 相关工具: payloads.JRMPListener:开启JRMP监听 payloads.JRMPClient:发送注册Ref exploit.JRMPListener:被动传输序列化payload exploit.JRMPClient:主动传输序列化payload 6. DGC(分布式垃圾回收) 跟踪远程对象在客户机中的使用 当引用过期且未更新时,服务器将垃圾回收远程对象 7. JNDI Reference攻击 Client执行lookup时加载远程恶意类实现RCE 防御: 6u141、7u131、8u121起默认trustURLCodebase=false JEP290对可反序列化类做白名单检测 8. 防御措施 升级JDK到安全版本 设置java.rmi.server.useCodebaseOnly=true 设置com.sun.jndi.rmi.object.trustURLCodebase=false 启用JEP290反序列化过滤机制 9. 攻击演示命令示例 bind攻击: JRMP监听: JRMP客户端攻击: