当前位置: 首页 > news >正文

代码审计 | Listener —— Tomcat 内存马 回显问题 反射总结

代码审计 | Listener —— Tomcat 内存马 回显问题 反射总结

目录

  • 前置:StandardContext 回顾

  • ApplicationEventDispatcher

  • ServletRequestListener 示例(静态注册)

  • web.xml 中注册 Listener 的标准写法

  • 动态注入 Payload(无回显版)

  • Listener 与 Filter/Servlet 的差异对比

  • 回显问题:为什么 Listener 不能直接回显?

  • 解决回显:反射硬拿 Response

  • 其他常见 Listener 接口简介

  • 反射补充:六大核心能力

  • 总结


前置:StandardContext 回顾

Listener 型内存马的注入原理,依然依赖于 Tomcat 内部的StandardContext

对象说明
StandardContextTomcat 中代表一个 Web 应用的核心对象,里面存了 Filter、Servlet、Listener等组件

可以用这个类比来理解三种组件的区别:

  • Filter:像一个安检闸机,所有请求都过一遍

  • Servlet:像一个具体柜台,请求最终被它处理

  • Listener:像一个感应门铃,有人进门(请求开始)、出门(请求结束)、新顾客到店(Session 创建)……都会触发

Listener 就存在StandardContextapplicationEventListeners字段里,执行调度器是ApplicationEventDispatcher,它负责从这个列表里取出 Listener 并调用。


ApplicationEventDispatcher

ApplicationEventDispatcher是 Tomcat运行时自动调用的调度器。

只要把 Listener 实例放进applicationEventListeners列表,Tomcat 在处理每个请求时,ApplicationEventDispatcher就会自动从列表里拿到你的 Listener 并调用它。

和 Filter 对比一下差异就很明显了:

  • 动态注册Filter:需要操作FilterDef+FilterMap+FilterChain(重新创建),比较繁琐

  • 动态注册Listener只操作一个列表,没有映射,没有链,简单得多


ServletRequestListener 示例(静态注册)

先看一个静态注册的ServletRequestListener,理解它的工作机制。

作用是:每次 HTTP 请求进入 Tomcat 时,自动执行requestInitialized方法;请求结束时执行requestDestroyed方法。

import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; import javax.servlet.annotation.WebListener; ​ // @WebListener 相当于在 web.xml 里注册 // 动态注入时不需要这个注解,因为我们是手动反射添加到 StandardContext 的 // applicationEventListeners 列表里,静态注册才需要注解或 web.xml @WebListener public class SimpleListener implements ServletRequestListener { ​    // 静态块:在类第一次被 JVM 加载时执行,只执行一次,这里只是调试用的    // 注意:动态注入的 Listener 是运行时创建的对象,不会触发静态块    static {        System.out.println("=== SimpleListener 类被加载了 ===");   } ​    // @Override 表示重写接口中的方法,Java 的语法习惯,不写也能运行    @Override    // 只要有请求就会进来,内存马中大部分核心恶意逻辑放在这里    public void requestInitialized(ServletRequestEvent sre) {        // 请求刚进来时执行        System.out.println("[Listener] 请求来了!");        System.out.println("请求的IP:" + sre.getServletRequest().getRemoteAddr()); ​        // 这里可以放恶意代码,比如:        // - 执行命令        // - 读取请求参数        // - 修改响应内容(不过需要拿到 response,稍麻烦)   } ​    @Override    // 只要请求结束就会触发,内存马中较少在这里放核心恶意逻辑    public void requestDestroyed(ServletRequestEvent sre) {        // 请求结束时执行        System.out.println("[Listener] 请求结束了");   } }

启动 Tomcat 服务后,类被加载就会显示:

每次刷新页面就会多一次输出,包含请求开始、IP 地址、请求结束三条日志:

这里 IP 显示的是0:0:0:0:0:0:0:1(简写::1),这是IPv6的本地回环地址,等价于 IPv4 的127.0.0.1


web.xml 中注册 Listener 的标准写法

静态注册除了用@WebListener注解,也可以写在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:sc
http://www.jsqmd.com/news/626329/

相关文章:

  • 嵌入式TFTP服务器库TFTPServer深度解析与移植指南
  • 微服务架构原则
  • MindSpore 环境配置完全指南志
  • Flutter开发环境搭建避坑指南:解决‘no devices‘等常见错误的5个关键步骤
  • TIP-2026《View-Adaptive Multi-Granularity Anchor Learning for Multi-View Clustering》
  • 可控性技术人工智能系统人类监督与干预接口设计
  • 不记命令也能排障:catpaw chat 实战手册叵
  • 让 AI 代理拥有“专业技能包“:Microsoft Agent Skills袒
  • 游戏引擎物理系统:刚体动力学与碰撞检测实现
  • React 18 并发渲染实战:useTransition、Suspense 与自动批处理深度解析
  • 电离层TEC地图中添加晨昏线/昼夜转换线
  • DataServeriOS:Arduino与iOS设备的轻量级TCP控制协议库
  • 一线汽车教师实测:迈腾380TSI电气故障仿真软件,破解教学与大赛双重痛点
  • 搜索引擎中的索引构建与查询处理
  • keepalived+nginx实现高可用
  • 论文复现基于改进人工鱼群法的机器人,无人机,无人车,无人船的路径规划算法,MATLAB
  • MATLAB读取TIF文件常见错误解析:从geotiffread报错到解决方案
  • TMP117高精度温度传感器I²C驱动深度解析
  • MPU6050裸机驱动开发:寄存器配置、I²C通信与姿态解算实战
  • 如何在5分钟内为你的Minecraft服务器添加RPG技能系统
  • EspATMQTT:面向资源受限MCU的ESP-AT MQTT轻量封装库
  • Sigrity SystemSI 2023实战:LPDDR4仿真报告生成避坑指南(从波形选择到阈值设置)
  • NusabotSimpleTimer:无中断轻量级软件定时器库
  • 别再只盯着VLM了!用VLA(Vision-Language-Action)模型手把手搭建你的第一个自动驾驶仿真环境
  • javaSE之图书管理系统
  • 【2026奇点大会AI语音交互终极指南】:3大原生架构、5类落地陷阱与2026Q2商用部署清单
  • 嵌入式上位机开发入门(十八):修复首次连接超时问题
  • Triton + RISC-V毓
  • Spring IOC 源码学习 声明式事务的入口点冻
  • ESP32/ESP8266工业级WiFi配置门户库