freeBuf
擅长捉弄的内存马同学:Listener内存马
2022-02-18 00:10:11

前言

上一篇文章我们说了一下Filter内存马,这篇文章我们继续说Listener内存马,相较于上一篇的这个内存马就简单了很多,如果已经明白了Filter内存马那篇文章,Listener内存马学起来会比较轻松,废话不多说,我们直接开始。

一、基础知识-Listener

在学Listener内存马之前首先我们需要先简单了解一下Listener。看过上一篇文章的小伙伴应该都了解了Tomcat和Servlet的关系,我们打Tomcat内存马也就是通过Tomcat的机制去调用我们自定义的Servlet(Filter型/ Listener型/Servlet型),我们学习Listener内存马,当然也就需要学习Listener了。

(一)Listener简介

监听器用于监听web应用中某些对象、信息的创建、销毁、增加,修改,删除等动作的发生,然后作出相应的响应处理。当域对象的状态发生变化的时候,服务器自动调用监听器对象中的方法。

通俗的语言说就是在application,session,request三个对象创建消亡或者往其中添加修改删除属性时自动执行代码的功能组件。

(二)Listener三个域对象

Listener的监听对象主要有三种类型。

(1)ServletContext域对象——实现ServletContextListener接口

生命周期:

  • 创建——启动服务器时创建
  • 销毁——关闭服务器或者从服务器移除项目

作用:利用ServletContextListener监听器在创建ServletContext域对象时完成一些想要初始化的工作或者执行自定义任务调度

(2)ServletRequest域对象——实现ServletRequestListener接口

生命周期:

  • 创建——访问服务器任何资源都会发送请求(ServletRequest)出现,访问.html和.jsp和.servlet都会创建请求。
  • 销毁——服务器已经对该次请求做出了响应。

(3)HttpSession域对象——实现HttpSessionListener接口

生命周期:

  • 创建——只要调用了getSession()方法就会创建,一次会话只会创建一次,
  • 销毁——1.超时(默认为30分钟) // 2.非正常关闭,销毁 // 3.正常关闭服务器(序列化)

作用:每位用户登录网站时都会创建一个HTTPSession对象,利用这个统计在线人数。

(三)Listener实现

根据我们上面看到的知识,可以看出ServletRequest类型是比较适合内存马的实现,所以我们跟到该接口进行查看。

我们编写一个简单的Listener来进行测试。

到这里已经我们已经简单实现了一个监听器,接下来我们就开始分析监听器的执行流程,这里和Filter其实很像,我们从应用启动开始分析。

二、Filter流程分析

(一)ContextConfig读取配置文件(应用启动过程)

首先我们在启动应用的时候会ContextConfig会去读取配置文件,所以我们首先定位到configureContext.class,我们找到读取listener的部分。可以看到这里读取了webxml中的listeners,做了一个迭代器后执行addApplicationListener(listener),我们跟进去查看一下。

可以看到这个接口的实现类为StandardContext,跟进去查看一下。我们可以看到addApplicationListener方法将listener添加进了applicationListeners。

(二)StandardContext执行listenerStart(应用启动过程)

当我们读取完配置文件,当应用启动的时候,StandardContext会去调用filterStart方法。我们跟到filterStart方法的位置进行分析。可以看到首先我们先会去执行findApplicationListeners方法,我们跟进去看一下。

跟到find ApplicationListeners,此时他读取了StandardContext的applicationListeners,这里也就是我们上一步读取配置后存入的位置。我们回到刚才的位置。

此时可以看到我们将读取到的listeners存入listeners后实例化了一个results,接着对其进行了一个遍历,依次执行了results[i] = this.getInstanceManager().newInstance(listener);其实从这里我们应该就知道了,这段代码其实就是通过findApplicationListeners读取listeners并将其依次实例化后放到result中。我们继续向下看代码。

我们正常进入循环,首先进行了一次类型判断,由于我们的类型是ServletRequestListener,所以我们的listener添加到了eventListeners中。接下来执行getApplicationEventListeners 方法来获取 applicationEventListenersList 属性(这是是已注册的Listener列表),之后执行setApplicationEventListeners方法,通过方法名我们应该也能知道这里会设置listeners。我们跟进去看一看这个方法。

跟到setApplicationEventListeners方法,这里首先对applicationEventListenersList属性进行了清空,然后将我们的listener全部放到applicationEventListenersList属性中。到这里为止我们已经知道启动后将我们的listener实例存储到了applicationEventListenersList属性中。

(三)StandardContext执行requestInitialized

我们启动应用后,访问url看看他是怎么进行运行的。观察栈的信息我们跟进去看一下。

可以看到我们的请求是在这里执行的,我们定位到方法的位置。

我们找到了StandardContext方法,分析代码,首先通过getApplicationEventListeners()获取到Listeners,这个方法很熟悉吧,我们之前获取Listeners就是用的这个方法。接下来如果存在我们获取当前的ServletRequestEvent,对其进行遍历判断类型并转成ServletRequestListener后,执行listener.requestInitialized(event),也就是在这里触发了我们的方法。

分析到这里我们可以得知,我们其实只需要将恶意的Listener打入applicationEventListenersList中就OK了,比Filter内存马简单很多。

三、Listener内存马实现

接下来我们就开始进行内存马的编写,我们在上一篇文章说过StandardContext的获取方法,这块不清楚的师傅可以去看一下上一篇文章,我们获取到StandardContext就可以直接反射获取addApplicationEventListener方法,然后把我们的恶意Listener添加进去就行了。

1645117509_620e80459c0ec6f0d3f22.png!small?1645117515411

1645117639_620e80c72f7cbc1e14909.png!small?1645117644191

参考文章

Java Listener内存马 

Tomcat容器攻防笔记之Listener内存马

Listener 介绍

Java监听器Listener使用详解

Listener(监听器)的简单介绍

tomcat server.xml配置属性

本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
文章目录