讲下 RMI 原理以及相关的漏洞
1. RMI 原理
RMI(Remote Method Invocation),是 Java 远程方法调用的缩写。简单来说,它是一种 Java 编程技术,允许你在一个 Java 虚拟机(JVM)上运行的代码,调用另一个不同 JVM 上的对象的方法。这使得分布式应用开发变得相对简单,因为你可以像调用本地对象一样调用远程对象的方法
RMI 的核心思想是存根(Stub)和骨架(Skeleton)
- 客户端(Client):
- 存根(Stub):这是一个本地代理对象,它实现了远程对象的接口。客户端调用远程方法时,实际上是在调用存根上的本地方法。存根负责将方法调用信息(方法名、参数等)打包,并发送给远程服务器
- 服务器端(Server):
- 远程对象(Remote Object):这是真正提供服务、执行方法的对象
- 骨架(Skeleton):一个中间层对象,它监听客户端的请求。当收到存根发来的请求时,骨架负责解析请求,找到相应的远程对象,调用其方法,并将结果打包返回给客户端
RMI 工作流程
- 注册:服务器端创建一个远程对象,并通过一个注册中心(RMI Registry)将其注册。注册中心会绑定远程对象和服务名,例如
rmi://server:port/serviceName
- 查找:客户端通过服务名向注册中心查找远程对象。注册中心会返回一个存根对象给客户端
- 调用:客户端调用存根上的方法
- 传输:存根将方法调用信息序列化并通过网络发送给服务器端的骨架
- 执行:骨架反序列化信息,调用远程对象上的实际方法,并将结果序列化后返回
- 返回:客户端的存根接收到结果并反序列化,然后返回给客户端
2. RMI 相关漏洞
RMI 的安全问题主要源于其依赖 Java 对象的序列化和反序列化机制。这种机制本身就是高风险的,因为它默认信任所有传入的对象。攻击者可以利用这一特性,构造恶意的序列化对象,在反序列化时触发攻击
漏洞一:RMI 序列化漏洞(反序列化漏洞)
这是 RMI 最常见也是最危险的漏洞类型。
- 原理:在 RMI 的调用过程中,客户端和服务端会相互发送序列化的对象。攻击者可以利用这个机制,构造一个包含恶意 Payload 的序列化对象。当服务器在反序列化这个对象时,如果其所依赖的库中存在可被利用的 Gadget Chain(例如
Apache Commons Collections
),就会导致远程代码执行(RCE) - 攻击利用:攻击者首先需要确定 RMI 服务器的地址和端口。然后,他们会使用工具(例如
ysoserial
)来生成一个恶意的序列化 Payload。最后,通过向 RMI 接口发送这个 Payload,即可触发反序列化攻击 - 影响:这是一种高危 RCE 漏洞,可以使攻击者在未授权的情况下完全控制服务器
漏洞二:RMI 弱口令漏洞
- 原理:如果 RMI Registry 的管理接口存在弱口令,攻击者就可以登录并执行恶意操作
- 攻击利用:攻击者可以尝试对 RMI Registry 的管理接口进行暴力破解或字典攻击。一旦获得权限,就可以修改、删除或注册恶意服务
漏洞三:RMI Registry 绑定漏洞
- 原理:某些情况下,RMI Registry 允许任何客户端绑定新的远程对象。如果应用程序没有对这个功能进行严格的权限控制,攻击者就可以注册一个恶意的远程对象
- 攻击利用:攻击者可以注册一个带有恶意方法的远程对象。然后,他们可以诱导受害者或通过其他方式调用这个恶意方法,从而实现攻击
漏洞四:RMI SSL/TLS 证书验证漏洞
- 原理:RMI 可以配置为使用 SSL/TLS 进行安全通信。但如果客户端没有正确验证服务器的 SSL 证书,攻击者就可以进行中间人攻击(MitM),从而窃取敏感信息或篡改通信内容