原标题:RMI 远程命令执行分析

一、 RMI 简介

RMI是Remote Method Invocation的简称,是J2SE的一部分,能够让程序员开发出基于Java的分布式应用。一个RMI对象是一个远程Java对象,可以从另一个Java虚拟机上(甚至跨过网络)调用它的方法,可以像调用本地Java对象的方法一样调用远程对象的方法,使分布在不同的JVM中的对象的外表和行为都像本地对象一样。

而 RMI 对于远程对象的调用使用了 Java 的序列化和反序列化。

二、Java 反序列化漏洞

Java序列化是将我们的java对象封装成静态二进制格式,这样就适合存储在磁盘上或者通过网络传输。而当系统环境中存在漏洞 jar 包时,会导致远程命令执行(RCE)。具体可参见http://www.angelwhu.com/blog/?p=394。

三、典型漏洞写法

项目功能是调用 RMI 来打印欢迎信息,目录结构如下:




首先运行 Run.java,控制台打印:

然后运行 MyRmiClient.java,控制台打印:


说明我们的 RMI 服务已经能正常使用了。

四、风险分析

嗯, RMI 确实很方便,调用远程的服务就像使用本地对象一样。悲剧的是,方便的同时却引来了潜在的危害。

我们看一下本地监听的端口情况:


我代码中明明写的是 127.0.0.1 这个 ip 啊,为什么监听到了 0.0.0.0?

那如果此时环境中刚好有存在反序列化漏洞的 jar 包,岂不是就直接远程命令执行了?

为了验证,我在工程中加入了 commons-collections-3.1.jar


然后我在同网段的其他电脑上使用 ysoserial 来执行命令:java -cp ysoserial-0.0.4-all.jar ysoserial.exploit.RMIRegistryExploit 8.8.8.8 6600 CommonsCollections1 "calc"

注:8.8.8.8 是我的外网 ip,ysoserial-0.0.4-all.jar 下载地址

https://github.com/frohoff/ysoserial/archive/v0.0.4.zip


见到可以成功执行。

五、缓解措施

我们知道要造成 RMI 命令执行有两个条件:1、RMI 对外开放;2、系统环境中存在有漏洞 Jar 包。那么缓解措施也是针对以上两个条件来做。

1、使 RMI 只开放在内网

之前的写法


我们以为只会监听 127.0.0.1,但现实是监听了所有的网卡,此时正确的写法如下:


即使用

Registry java.rmi.registry.LocateRegistry.createRegistry(int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException

方法来指定监听的网卡。


此时就监听到了 127.0.0.1 上,远程已经无法访问。

2、升级本地的 jar 包。

目前网上公布的存在漏洞的 jar 包版本,可以参考 https://github.com/frohoff/ysoserial/tree/master/src/main/java/ysoserial/payloads。

参 考

https://github.com/frohoff/ysoserial

http://www.blogjava.net/zhenyu33154/articles/320245.html

http://www.angelwhu.com/blog/?p=394