可利用类

利用java.lang.Runtime 实现RCE

java.lang.Runtime里面有exec方法可以执行命令

利用java.lang.ProcessBuilder 实现RCE

暂未研究


RCE(java.lang.RunTime为例)

思路

1.构造存在rce的类
2.构造存在rce的方法method
3.构造此类的实例对象obj
4.利用obj通过method(invoke)来rce

基本流程

  • 利用Class.forname()获取命令执行的类
  • 利用Class.getMethod()查找命令执行的方法
  • 利用Class.newInstance()获取命令执行的对象
  • 利用获取的方法构造invoke方法
1
method.invoke(obj,args)

method->方法名
obj->方法实例对象
args->参数 多个参数用”,”隔开


正常:
静态方法:类名.方法名
函数方法:对象.方法名

反射(invoke):
方法名.invoke(类名,参数)
静态方法:方法名.invoke(null,参数)
函数方法:方法名.invoke(对象,参数)

测试

思路

1.获取Runtime类
2.实例化一个Runtime对象
3.获取其exec方法
4.传参调用exec方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class<?> c1 = Class.forName("java.lang.Runtime");
System.out.println(c1);
for (Method method : c1.getMethods()) {
System.out.println(method);
}
Method exec = c1.getMethod("exec", String.class);
Object obj = c1.newInstance();
Object calc = exec.invoke(obj, "calc");
}

}

以上代码会报错

这是因为java.lang.Runtime中的构造方法是私有的,当执行c1.newInstance()时本质是调用了类的无参构造器

绕过思路: 由于类初始化的时候会先对类中的所有静态方法进行调用,所以我们的思路就是利用静态方法getRuntime()来实现绕过

获取Runtime的静态方法getRuntime(),调用方法来获取Runtime对象,再通过这个对象来调用exec方法

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
33
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;



public class Test {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, IOException {
Class<?> c1 = Class.forName("java.lang.Runtime");
// System.out.println(c1);
// for (Method method : c1.getMethods()) {
// System.out.println(method);
// }
Method getRuntime = c1.getMethod("getRuntime");
Method exec = c1.getMethod("exec", String.class);
Object obj = getRuntime.invoke(null);
Process p = (Process) exec.invoke(obj, "whoami"); //这里换成Process是因为需要调用Process类的方法如getInputStream()来读取命令执行的文件流

//读取命令执行的文件流
InputStream inputStream = p.getInputStream(); //获取进程的标准输出流(命令执行之后的输出)
InputStreamReader inputStreamReader = new InputStreamReader(inputStream); //利用InputStreamReader将字节流(InputStream)转换成字符流(Reader)
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);//使用字符流的方式来读取输入

String line = null;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
}

}

RCE成功


参考

从Java反射机制到RCE