java审计-rmi协议
RMI
RMI是Remote Method Invocation,远程方法调用。是让java虚拟机上的对象调用另一个java虚拟机中对象上的方法。
RMI Server:
package org.vulhub.RMI; |
分析:
LocateRegistry.createRegistry(1099); |
第一行创建并运行RMI Registry,第二行将Rexxx对象绑定到Hello这个名字上。
Naming.bind的第一个参数是一个URL,形如:rmi://host:port/name。其中,host和port就是RMI Registry的地址和端口,name是远程对象的名字。
如果RMI Registry在本地运行,则host和port可以省略,默认为1099
RMI client:
package org.vulhub.Train; |
通信分析
整个通信过程进行了两次TCP握手,建立了两次TCP连接,首先客户端连接Registry,并在其中寻找Name是Hello的对象,这个对应数据流中的Call消息,然后Registry返回一个序列化的数据,这个就是找到的Name=Hello的对象,这个对应数据流中的ReturnData消息;客户端反序列化该对象,发现该对象是一个远程对象
RMI Registry就像⼀个⽹关,他⾃⼰是不会执⾏远程⽅法的,但RMI Server可以在上⾯注册⼀个Name到对象的绑定关系;RMI Client通过Name向RMI Registry查询,得到这个绑定关系,然后再连接RMIServer;最后,远程⽅法实际上在RMI Server上调⽤。
安全问题
1.list+lookup远程调用
list方法可以列出目标上所有绑定的对象:
String[] s= Naming.list("rmi://xxx"); |
而lookup作用就是获得某个远程对象,若存在危险方法,则可进行调用
2.RMI利用codebase执行任意代码
codebase:是一个地址,告诉java虚拟机我们应该从哪个地方去搜索类,通常是远程URL、比如http、ftp等。
如果我们指定codebase=http://exampl.com/,然后加载org.vulhub.example.Example类,则java虚拟机会下载这个文件http://example.com/org/vulhub/example/Example.class ,并作为Example类的字节码。
RMI流程中,反序列化时发现一个对象,先会在CLASSPAATH下寻找,若没找到,则会远程加载codebase中的类。
攻击条件
- codebase可控
- 安装并配置了SecurityManager
- Java版本低于7u21、6u45,或者设置了java.rmi.server.useCodebaseOnly=false其中java.rmi.server.useCodebaseOnly是在Java 7u21、6u45的时候修改的一个默认设置:
- https://docs.oracle.com/javase/7/docs/technotes/guides/rmi/enhancements-7.html
- https://www.oracle.com/technetwork/java/javase/7u21-relnotes-1932873.html
PS:当java.rmi.server.useCodebaseOnly为true时,java虚拟机将只信任预先配置好的codebase。
classAnnotations
可以使用SerializationDumper查看数据包中的java反序列化内容
通过修改classAnnotations可以控制codebase。