原标题: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