RMI Remote Object反序列化攻击
字数 1562 2025-08-09 15:23:02
RMI Remote Object反序列化攻击分析
1. RMI基础概念
RMI (Remote Method Invocation) 是Java中的远程方法调用机制,允许一个JVM中的对象调用另一个JVM中对象的方法。RMI的核心机制依赖于Java的序列化/反序列化技术来传递对象信息。
2. RMI通信流程
- 客户端调用远程方法:客户端通过stub调用远程方法
- 参数序列化:客户端将方法参数序列化为字节流
- 网络传输:序列化后的数据通过网络传输到服务端
- 服务端反序列化:服务端接收并反序列化参数
- 方法执行:服务端执行实际方法
- 结果返回:服务端序列化结果并返回给客户端
3. 反序列化攻击原理
RMI的核心安全问题在于其依赖Java反序列化机制,而Java反序列化存在以下风险点:
- 客户端可控数据:客户端发送的序列化数据完全可控
- 服务端自动反序列化:服务端会自动反序列化接收到的数据
- 反序列化漏洞:Java反序列化过程中可能执行恶意代码
4. 攻击面分析
4.1 攻击点1:参数传递
当客户端向服务端传递方法参数时:
- 参数对象会被序列化
- 攻击者可构造恶意序列化对象
- 服务端反序列化时可能触发漏洞
4.2 攻击点2:返回值处理
当服务端向客户端返回结果时:
- 返回对象会被序列化
- 恶意服务端可构造恶意序列化对象
- 客户端反序列化时可能触发漏洞
4.3 攻击点3:RMI注册中心
RMI Registry同样存在反序列化问题:
- 绑定/查找操作涉及对象传输
- 攻击者可针对Registry发起攻击
5. 漏洞利用条件
- 存在可访问的RMI服务端点
- 服务端使用了存在漏洞的Java版本
- 服务端反序列化过程中使用了存在危险功能的类
- 攻击链中的必要类在目标classpath中可用
6. 常见攻击场景
6.1 攻击RMI服务端
- 识别开放的RMI端口(默认1099)
- 枚举可用的远程对象
- 构造恶意序列化payload
- 通过方法调用发送payload
6.2 攻击RMI Registry
- 直接连接Registry端口
- 使用恶意序列化数据进行bind/lookup操作
- 利用Registry的反序列化漏洞执行代码
7. 防御措施
7.1 代码层面
- 使用
ObjectInputFilter限制反序列化类System.setProperty("jdk.serialFilter", "!*"); - 自定义
ObjectInputStream并重写resolveClass方法public class SafeObjectInputStream extends ObjectInputStream { @Override protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { // 白名单校验逻辑 } }
7.2 配置层面
- 升级JDK到最新版本
- 配置JVM参数限制反序列化
-Djdk.serialFilter=<filter pattern> - 使用安全管理器限制权限
7.3 架构层面
- 使用RMI替代方案如Hessian、gRPC等
- 在网络边界过滤RMI流量
- 使用SSL/TLS加密RMI通信
8. 漏洞检测方法
- 端口扫描识别RMI服务(1099)
- 使用工具测试反序列化漏洞:
- ysoserial
- marshalsec
- RMIScout
- 手工构造payload验证
9. 相关CVE
- CVE-2017-3241: Java RMI Registry反序列化漏洞
- CVE-2018-2634: RMI通过JRMP协议的反序列化漏洞
- CVE-2019-2684: RMI通过JNDI的漏洞
10. 工具推荐
- ysoserial:生成各种反序列化payload
- marshalsec:快速启动恶意RMI/LDAP服务
- RMIScout:RMI枚举和漏洞检测工具
- BaRMIe:RMI枚举和攻击工具
11. 实际攻击示例
// 使用ysoserial生成payload
String[] command = {"calc.exe"};
final Object payload = new CommonsCollections5().getObject(command);
// 攻击RMI Registry
Registry registry = LocateRegistry.getRegistry("target", 1099);
Field field = registry.getClass().getDeclaredField("ref");
field.setAccessible(true);
RemoteRef ref = (RemoteRef) field.get(registry);
RefAddr addr = new RefAddr("payload") {
public Object getContent() { return payload; }
};
Reference reference = new Reference("Exploit", addr, "Exploit", null);
ref.invoke(new RemoteCall(
null, "bind", new Object[]{ "pwned", reference }, new long[]{0}
));
12. 总结
RMI反序列化攻击是Java安全领域的重要议题,其核心问题在于:
- RMI协议设计上完全信任客户端数据
- Java反序列化机制本身存在安全隐患
- 历史版本中存在大量可利用的gadget链
防御的关键在于严格控制反序列化过程,使用白名单机制限制可反序列化的类,并及时更新Java运行环境。