java安全-常见危险类
java安全-危险类
一、Runtime命令执行
1.Runtime类
Runtime是 JDK 自带、位于 java.lang 包中的类,每个 JVM 进程内部只有一个 Runtime 实例。
正常调用计算机方式:
1 | Runtime rt = Runtime.getRuntime(); |
2.类详解
类中方法
exec方法
1
2
3
4
5
6
7
8public Process exec(String[] cmdarray, String[] envp, File dir)
throws IOException {
return new ProcessBuilder(cmdarray)
.environment(envp)
.directory(dir)
.start();
}
rt.exec("calc.exe");getRuntime方法
因为他是单例类,所以在创建类时需要使用其内部提供的构造方法
1
2
3
4
5
6Method getRuntimeMethod = clazz.getMethod("getRuntime");
Runtime runtime = (Runtime) getRuntimeMethod.invoke(null);
Method execMethod = clazz.getMethod("exec", String.class);
execMethod.invoke(runtime, "calc.exe");
Class.forName("java.lang.Runtime").getMethod("exec",String.class).invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(null),"calc");//最短代码
实现命令回显
当你调用 exec 时,它返回的是一个 java.lang.Process 对象。命令的执行结果(比如 whoami 输出的用户名)是在这个 Process 对象的 InputStream(输入流) 里的。于是,实现下面步骤即可
- 执行
exec,得到Process对象。 - 反射调用
Process的getInputStream()方法。 - 读取流中的数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16Class<?> clazz = Class.forName("java.lang.Runtime");
Method getRuntimeMethod = clazz.getMethod("getRuntime");
Runtime runtime = (Runtime) getRuntimeMethod.invoke(null);
Method execMethod = clazz.getMethod("exec", String.class);
// 执行命令
Object process = execMethod.invoke(runtime, "ipconfig");
Class<?> processClass = Class.forName("java.lang.Process");
Method getInputStreamMethod = processClass.getMethod("getInputStream");
java.io.InputStream is = (java.io.InputStream) getInputStreamMethod.invoke(process);
Scanner scanner = new Scanner(is, "GBK").useDelimiter("\\A");
String output = scanner.hasNext() ? scanner.next() : "";
System.out.println("命令回显结果:\n" + output);或
1
2
3
4
5
6
7
8
9
10public static void main(String[] args) throws Exception {
InputStream inputStream = Runtime.getRuntime().exec("whoami").getInputStream();
byte[] cache = new byte[1024];
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int readLen = 0;
while ((readLen = inputStream.read(cache))!=-1){
byteArrayOutputStream.write(cache, 0, readLen);
}
System.out.println(byteArrayOutputStream);
}- 执行
二、ProcessBuilder命令执行
1.ProcessBuilder类
ProcessBuilder是 Java 推荐的用于创建操作系统进程的方式。
正常调用计算机方式:
1 | ProcessBuilder processBuilder = new ProcessBuilder("calc"); |
2.类详解
构造方法
1
2public ProcessBuilder(List<String> command) {
public ProcessBuilder(String... command) {传入的参数即为执行命令,但是需要分开传递,例如:
ProcessBuilder pb = new ProcessBuilder("ping", "-n", "3", "www.google.com");start方法
这是实际执行命令的方法。它会返回一个
Process对象,代表正在运行的子进程。反射链调用
1
2
3
4
5
6
7传参为列表
Class clazz = Class.forName("java.lang.ProcessBuilder");
clazz.getMethod("start").invoke(clazz.getConstructor(List.class).newInstance(Arrays.asList("calc")));
//这里传参为列表,
传参为数组
Class clazz = Class.forName("java.lang.ProcessBuilder");
clazz.getMethod("start").invoke(clazz.getConstructor(String[].class).newInstance(new String[][]{{"calc"}}));//这里传参为数组回显命令
1
2
3
4
5
6
7
8
9
10public static void main(String[] args) throws Exception {
InputStream inputStream = new ProcessBuilder("ipconfig").start().getInputStream();
byte[] cache = new byte[1024];
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int readLen = 0;
while ((readLen = inputStream.read(cache))!=-1){
byteArrayOutputStream.write(cache, 0, readLen);
}
System.out.println(byteArrayOutputStream);
}
三、ProcessImpl命令执行
1.ProcessImpl类
- 平时用的
Runtime.exec()或者ProcessBuilder.start(),其实都只是“中介”。它们最终都会调用java.lang.ProcessImpl(在 Windows 上)或java.lang.UNIXProcess(在 Linux/JDK8 及更早版本上)来真正执行系统命令。
他没有公开构造方法,所以只能通过反射调用该类
2.类详解
start方法1
2
3
4
5static Process start(String cmdarray[],
java.util.Map<String,String> environment,
String dir,
ProcessBuilder.Redirect[] redirects,
boolean redirectErrorStream)具体参数如上,他是一个静态方法
依旧返回Process对象
3.反射链
回显
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
45public static void main(String[] args) throws Exception {
// 1. 获取底层类
Class<?> clazz = Class.forName("java.lang.ProcessImpl");
// 2. 获取 start 静态方法
Method startMethod = clazz.getDeclaredMethod("start",
String[].class, // 1. cmdarray
Map.class, // 2. environment
String.class, // 3. dir
ProcessBuilder.Redirect[].class, // 4. redirects (这里是数组类型!)
boolean.class // 5. redirectErrorStream
);
// 3. 暴力破解权限
startMethod.setAccessible(true);
// 4. 构造参数
String[] cmd = new String[]{"ipconfig"};
// 5. 调用 invoke
// 注意第4个参数传 null。
// 根据源码:if (redirects == null) { stdHandles = ... }
// 传 null 会让它自动去生成默认的 stdHandles,非常完美。
Object processObj = startMethod.invoke(null,
cmd,
null, // environment
null, // dir
null, // redirects (关键点:传 null)
false // redirectErrorStream
);
// --- 6. 命令回显部分 ---
// 拿到 Process 对象,读取输出流
java.lang.Process process = (java.lang.Process) processObj;
java.io.InputStream is = process.getInputStream();
// Windows 默认编码通常是 GBK
Scanner scanner = new Scanner(is, "GBK").useDelimiter("\\A");
String output = scanner.hasNext() ? scanner.next() : "";
System.out.println("--- ProcessImpl 成功调用 ---");
System.out.println(output);
}
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 十七.!
