Java命令执行总结

特殊符号&、&&、|、||

特殊符号 描述
& 表示与,a&b,条件a和条件b都执行了
| 表示或,a|b,条件a和条件b都执行了
&& 表示与,短路与,a&&b当条件a错误不会执行条件b
|| 表示或,短路或,a||b当条件a正确不会执行条件b

在Windows或者Linux下执行命令时,会将|作为管道符,将两个应用程序连接在一起,把第一个应用程序的输出作为第二个应用程序的输入。

另外Linux执行命令还有一个特殊符号;,多个命令顺序执行,命令之间无任何逻辑关系:

1
ls;echo 123

有一个坑点需要提示:

|连接两个命令,前后命令都会执行,只不过不会再控制台显示第一个命令执行的结果,比如dir|echo 123或者ls|echo 123,所以导致有人认为第一个命令没有被执行,可以用touch file|echo 111来证实,执行命令后会创建文件123

Java命令执行

Java关键字:

1
2
3
4
5
Runtime.exec
Process
ProcessBuilder.start
ProcessImpl
...

在Java中命令执行最常用的有两个Runtime.execProcessBuilder.start

Runtime执行命令示例

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
public class RuntimeCmdInject {
public static void main(String[] args) {
RuntimeCmdInject runtimeCmdInject = new RuntimeCmdInject();
// runtimeCmdInject.cmdNoFix("ipconfig /all");
runtimeCmdInject.cmdNoFix_1("127.0.0.1&echo 123321");
}

private void cmdNoFix(String cmd) {
try {
Process exec = Runtime.getRuntime().exec(cmd);
BufferedInputStream bufferedInputStream = new BufferedInputStream(exec.getInputStream());
byte[] bytes = new byte[1024];
int len;
while ((len = bufferedInputStream.read(bytes)) != -1) {
System.out.write(bytes, 0, len);
}
bufferedInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}

}

private void cmdNoFix_1(String ip) {
try {
Process exec = Runtime.getRuntime().exec(new String[]{"cmd", "/k", "ping " + ip});
BufferedInputStream bufferedInputStream = new BufferedInputStream(exec.getInputStream());
byte[] bytes = new byte[1024];
int len;
while ((len = bufferedInputStream.read(bytes)) != -1) {
System.out.write(bytes, 0, len);
}
bufferedInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}

}

private void cmdWithFix(String ip) {
try {
// 特殊字符检查
String[] blackChar = {"&", "|", ";"};
for (String s : blackChar) {
if (ip.contains(s)) {
return;
}
}
// 正则匹配IP或者域名
String pattern = "(^\\d+(\\.\\d+){2}\\.\\d+$)|([a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\\.?)";
boolean ismatch = Pattern.matches(pattern, ip);
if(!ismatch){
return;
}
Process exec = Runtime.getRuntime().exec(new String[]{"ping", ip});
BufferedInputStream bufferedInputStream = new BufferedInputStream(exec.getInputStream());
byte[] bytes = new byte[1024];
int len;
while ((len = bufferedInputStream.read(bytes)) != -1) {
System.out.write(bytes, 0, len);
}
bufferedInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}

}
}

ProcessBuilder执行命令示例

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
public class ProcessCmdInject {
public static void main(String[] args) {
ProcessCmdInject processCmdInject = new ProcessCmdInject();
processCmdInject.cmdNoFix_1("127.0.0.1|echo 123");
}

private void cmdNoFix(String[] cmd) {
try {
Process process = new ProcessBuilder(cmd).start();
InputStream inputStream = process.getInputStream();
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
byte[] bytes = new byte[1024];
int len;
while ((len = bufferedInputStream.read(bytes)) != -1) {
System.out.write(bytes, 0, len);
}
bufferedInputStream.close();

} catch (IOException e) {
e.printStackTrace();
}
}

private void cmdNoFix_1(String ip) {
try {
Process process = new ProcessBuilder(new String[]{"cmd","/K", "ping " + ip}).start();
InputStream inputStream = process.getInputStream();
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
byte[] bytes = new byte[1024];
int len;
while ((len = bufferedInputStream.read(bytes)) != -1) {
System.out.write(bytes, 0, len);
}
bufferedInputStream.close();

} catch (IOException e) {
e.printStackTrace();
}
}

private void cmdWithFix(String ip) {
try {
// 特殊字符检查
String[] blackChar = {"&", "|", ";"};
for (String s : blackChar) {
if (ip.contains(s)) {
return;
}
}
// 正则匹配IP或者域名
String pattern = "(^\\d+(\\.\\d+){2}\\.\\d+$)|([a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\\.?)";
boolean ismatch = Pattern.matches(pattern, ip);
if(!ismatch){
return;
}
Process process = new ProcessBuilder(new String[]{"ping " + ip}).start();
InputStream inputStream = process.getInputStream();
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
byte[] bytes = new byte[1024];
int len;
while ((len = bufferedInputStream.read(bytes)) != -1) {
System.out.write(bytes, 0, len);
}
bufferedInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}

}

}

:warning:需要注意:

一些单纯的拼接并不能造成我们预期的命令执行效果,可以参考大佬文章Java下奇怪的命令执行。如果不是以bin/bash或者cmd.exe这类支持特殊命令参数的命令开始,那么一般情况下不会造成严重的命令执行漏洞。

参考链接:

1
2
3
https://blog.zeddyu.info/2019/01/17/%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C/
http://www.lmxspace.com/2019/10/08/Java%E4%B8%8B%E5%A5%87%E6%80%AA%E7%9A%84%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C/
https://xz.aliyun.com/t/7046