Java利用技巧:通過反射實現webshell編譯文件的自刪除
0x00 前言
我們知道,當我們訪問jsp文件時,Java環境會先將jsp文件轉換成.class字節碼文件,再由Java虛擬機進行加載,這導致了Java服務器上會生成對應名稱的.class字節碼文件。對于webshell,這會留下痕跡。
為了實現自刪除.class字節碼文件,我們可以通過反射獲得.class字節碼文件的路徑,再進行刪除。本文將以Zimbra環境為例,結合AntSword-JSP-Template,分析利用思路。
0x01 簡介
本文將要介紹以下內容:
?通過反射實現webshell編譯文件的自刪除
?通過反射實現AntSword-JSP-Template
0x02 通過反射實現webshell編譯文件的自刪除
根據上篇文章《Java利用技巧——通過反射修改屬性》的內容,我們按照映射request->_scope->_servlet->rctxt->jsps,通過多次反射最終能夠獲得JspServletWrapper實例
查看JspServletWrapper類中的成員,jsps->value->ctxt->servletJavaFileName保存.java編譯文件的路徑,jsps->value->ctxt->classFileName保存.class編譯文件的路徑,示例如下圖

為了只篩選出當前jsp,可以通過request類的getServletPath()方法獲得當前Servlet,如下圖

從ctxt對象獲取servletJavaFileName可以調用JspCompilationContext類的getServletJavaFileName()方法,如下圖

從ctxt對象獲取classFileName可以調用JspCompilationContext類的getClassFileName()方法,如下圖

綜上,由此我們可以得出通過反射獲取編譯文件路徑的實現代碼如下:

刪除編譯文件的代碼如下:

0x03 通過反射實現AntSword-JSP-Template
rebeyond在《利用動態二進制加密實現新型一句話木馬之Java篇》介紹了Java一句話木馬的實現方法,AntSword-JSP-Template也采用了相同的方式
我在測試AntSword-JSP-Template的過程中,發現編譯文件會多出一個,例如test.jsp,訪問后,生成的編譯文件為test_jsp.class和test_jsp.java,如果使用了AntSword-JSP-Template,會額外生成編譯文件test_jsp$U.class
rebeyond在《利用動態二進制加密實現新型一句話木馬之Java篇》提到:
“正常情況下,Java并沒有提供直接解析class字節數組的接口。不過classloader內部實現了一個protected的defineClass方法,可以將byte[]直接轉換為Class
因為該方法是protected的,我們沒辦法在外部直接調用,當然我們可以通過反射來修改保護屬性,不過我們選擇一個更方便的方法,直接自定義一個類繼承classloader,然后在子類中調用父類的defineClass方法。”
這里我打算通過反射修改保護屬性,調用ClassLoader類的defineClass()方法
在ClassLoader類中,defineClass()方法有多個重載,如下圖

這里選擇defineClass(byte[] b, int off, int len)
rebeyond在《利用動態二進制加密實現新型一句話木馬之Java篇》還提到:
“如果想要順利地在equals中調用Request、Response、Seesion這幾個對象,還需要考慮一個問題,那就是ClassLoader的問題。JVM是通過ClassLoader+類路徑來標識一個類的唯一性的。我們通過調用自定義ClassLoader來defineClass出來的類與Request、Response、Seesion這些類的ClassLoader不是同一個,所以在equals中訪問這些類會出現java.lang.ClassNotFoundException異常”
解決方法同樣是復寫ClassLoader的如下構造函數,傳遞一個指定的ClassLoader實例進去:

最終,得到通過反射實現AntSword-JSP-Template的核心代碼:

訪問通過反射實現AntSword-JSP-Template的test.jsp后,額外生成的編譯文件為test_jsp$1.class
0x04 小結
本文介紹了通過反射實現webshell編譯文件自刪除和AntSword-JSP-Template,記錄關于反射的學習心得。