JAVA常见Sink点

总结一下JAVA中的一些常见Sink点。

命令执行

参考链接:

java.lang.Runtime#exec(java.lang.String)

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package Exec;  

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Scanner;

public class RuntimeDemo {
public static void main(String[] args) throws IOException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, ClassNotFoundException {
RuntimeExec();
RuntimeExecReflect1();
RuntimeExecReflect2();
RuntimeExecOutput1();
RuntimeExecOutput2();
RuntimeExecOutput3();
}

public static void RuntimeExec() throws IOException {
Runtime.getRuntime().exec("open -a Calculator.app");
}

public static void RuntimeExecReflect1() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException {
Class clazz = Runtime.class;
Method method = clazz.getMethod("getRuntime",null);
Runtime r = (Runtime) method.invoke(null,null);
r.exec("open -a Calculator.app");
}

public static void RuntimeExecReflect2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException, ClassNotFoundException {
Class clazz = Class.forName("java.lang.Runtime");
Method getRuntimeMethod = clazz.getMethod("getRuntime",null);
Method execMethod = clazz.getMethod("exec",String.class);
execMethod.invoke(getRuntimeMethod.invoke(null,null),"open -a Calculator.app");
}

public static void RuntimeExecOutput1() throws IOException {
Runtime runtime = Runtime.getRuntime();
Process execProcess = runtime.exec("whoami");

InputStream inputStream = execProcess.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
}
public static void RuntimeExecOutput2() throws IOException {
Runtime runtime = Runtime.getRuntime();
Process execProcess = runtime.exec("whoami");
InputStream inputStream = execProcess.getInputStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, len);
}
System.out.println(new String(byteArrayOutputStream.toByteArray()));
}

public static void RuntimeExecOutput3() throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// https://www.javasec.org/javase/CommandExecution/
String str = "whoami";
// 定义"java.lang.Runtime"字符串变量
String rt = new String(new byte[]{106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101});

// 反射java.lang.Runtime类获取Class对象
Class<?> c = Class.forName(rt);

// 反射获取Runtime类的getRuntime方法
Method m1 = c.getMethod(new String(new byte[]{103, 101, 116, 82, 117, 110, 116, 105, 109, 101}));

// 反射获取Runtime类的exec方法
Method m2 = c.getMethod(new String(new byte[]{101, 120, 101, 99}), String.class);

// 反射调用Runtime.getRuntime().exec(xxx)方法
Object obj2 = m2.invoke(m1.invoke(null, new Object[]{}), new Object[]{str});

// 反射获取Process类的getInputStream方法
Method m = obj2.getClass().getMethod(new String(new byte[]{103, 101, 116, 73, 110, 112, 117, 116, 83, 116, 114, 101, 97, 109}));
m.setAccessible(true);

// 获取命令执行结果的输入流对象:p.getInputStream()并使用Scanner按行切割成字符串
Scanner s = new Scanner((InputStream) m.invoke(obj2, new Object[]{})).useDelimiter("\\A");
String result = s.hasNext() ? s.next() : "";
System.out.println(result);
}

}

java.lang.ProcessBuilder#start

跟进Runtime.getRuntime().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
34
35
36
37
38
39
40
41
42
43
44
package Exec;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

public class ProcessBuilderDemo {
public static void main(String[] args) throws IOException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
ProcessBuilderExec();
ProcessBuilderReflect();
ProcessBuilderOutput();
}

public static void ProcessBuilderExec() throws IOException {
ProcessBuilder pb = new ProcessBuilder("open", "-a", "Calculator.app");
pb.start();
}

public static void ProcessBuilderReflect() throws IOException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
List<String> command = Arrays.asList("open", "-a", "/System/Applications/Calculator.app");

Class clazz = ProcessBuilder.class;
Constructor constructor = clazz.getConstructor(List.class);
Object pb = constructor.newInstance(command);
Method method = clazz.getMethod("start");
method.invoke(pb);
}

public static void ProcessBuilderOutput() throws IOException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
List<String> command = Arrays.asList("whoami");
ProcessBuilder pb = new ProcessBuilder(command);

InputStream inputStream = pb.start().getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
}

}

ProcessImpl.start

跟进java.lang.ProcessBuilder#start:

ProcessImpl执行命令只能反射调用。

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
34
35
36
37
38
39
package Exec;

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;
import java.util.Map;

public class ProcessImplDemo {
public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, IOException {
ProcessImplReflectExec();
ProcessImplReflectOutput();
}

public static void ProcessImplReflectExec() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
String[] cmdArray = new String[]{"open","-a","Calculator.app"};
Class clazz = Class.forName("java.lang.ProcessImpl");
Method method = clazz.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
method.setAccessible(true);
// start()为静态方法
method.invoke(null,cmdArray,null,null,null,true);
}

public static void ProcessImplReflectOutput() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException {
String[] cmdArray = new String[]{"whoami"};
Class clazz = Class.forName("java.lang.ProcessImpl");
Method method = clazz.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
method.setAccessible(true);
Process processImpl = (Process) method.invoke(null, cmdArray, null, null, null, true);
InputStream inputStream = processImpl.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
}
}

java.lang.UNIXProcess#UNIXProcess

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package Exec;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

public class UNIXProcessDemo {
public static void main(String[] args) throws Exception {
UnixProcessExec();
}

static byte[] toCString(String s) {
if (s == null) return null;
byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
byte[] result = new byte[bytes.length + 1];
System.arraycopy(bytes, 0, result, 0, bytes.length);
result[result.length - 1] = 0;
return result;
}

static byte[] toCStrings(String[] arr) {
if (arr == null || arr.length == 0) return new byte[]{0};
int totalLen = 0;
for (String s : arr) {
totalLen += s.getBytes(StandardCharsets.UTF_8).length + 1;
}
byte[] result = new byte[totalLen];
int pos = 0;
for (String s : arr) {
byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
System.arraycopy(bytes, 0, result, pos, bytes.length);
pos += bytes.length;
result[pos++] = 0;
}
return result;
}

public static void UnixProcessExec() throws Exception {
Class<?> clazz = Class.forName("java.lang.UNIXProcess");
Constructor<?> constructor = clazz.getDeclaredConstructor(
byte[].class, // prog
byte[].class, // argBlock
int.class, // argc
byte[].class, // envBlock
int.class, // envc
byte[].class, // dir
int[].class, // fds
boolean.class // redirectErrorStream
);
constructor.setAccessible(true);

String[] cmd = {"/bin/sh", "-c", "whoami"};

// prog -> argv[0]
byte[] prog = toCString(cmd[0]);

// argBlock -> 从 argv[1] 开始拼接
String[] realArgs = Arrays.copyOfRange(cmd, 1, cmd.length);
byte[] argBlock = toCStrings(realArgs);
int argc = realArgs.length;

// env
byte[] envBlock = null;
int envc = 0;

// fds
int[] std_fds = {-1, -1, -1};

Process process = (Process) constructor.newInstance(
prog, argBlock, argc,
envBlock, envc,
null, std_fds, false
);

InputStream inputStream = process.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}

}
}

==TODO==

  • forkAndExec
  • JNI
Author

iN1t0

Posted on

2025-09-09

Updated on

2025-09-11

Licensed under