内存马分析¶
Java内存马原理与利用¶
内存马简介¶
内存马是webshell的一种,不同于文件马,内存马无文件落地。顾名思义,内存马将恶意逻辑直接注入到目标 Java Web 应用程序的运行时内存中。内存马可以绕过文件监测系统,不易被定位和监控。在绕过安全设备和实现持久化控制上优于传统文件马。
Java内存马分类¶
按挂载点不同分为以下:
- Servlet-api类
- Spring类
-
Tomcat Valve 内存马
-
MBean 内存马
-
Agent 内存马

内存马的生命周期¶
内存马的生命周期与 Web 容器、应用部署、JVM 运行状态紧密相关。
内存马自注入到运行中的web容器开始,随容器运行,一般在web容器、web服务停止/重启时死亡。
不同类型的内存马的生命周期有区别,与其挂载点有关。总结就是:
内存马的生命周期 = 它所寄生组件的生命周期。清除内存马的本质,是摧毁其寄生环境 —— 重部署、重启、或 JVM 终结
web应用重启指重启对应的web应用(tomcat可能同时运行不同web应用),影响较小。JVM重启指重启tomcat服务sudo systemctl restart tomcatv,影响所有web应用。
各类型内存马生命周期具体如下
| 类型 | 生命周期起点 | 生命周期持续阶段 | 生命周期终点 | 是否可热清除(不重启JVM) |
|---|---|---|---|---|
| Filter | addFilter() 成功执行或反射注入完成 |
持续拦截请求,除非被移除或上下文销毁 | Web 应用 reload / undeploy / 重启 | ✅ 是(重部署即可) |
| Servlet | addServlet() 成功执行或反射注入完成 |
响应特定路径,除非被移除 | Web 应用 reload / undeploy / 重启 | ✅ 是 |
| Listener | addListener() 或应用启动时初始化 |
随 Context/Session 生命周期持续运行 | Web 应用 stop / 重启 | 部分(如HttpSession相关) |
| Spring Controller | 注入到 HandlerMapping 成功 |
随 Spring MVC 分发器持续生效 | /refresh / Context 重启 / 应用重启 |
✅ 是(/refresh 即可) |
| Spring Intercepto | 成功注入到 HandlerMapping.interceptorList |
所有匹配请求经 Spring MVC 分发时被调用 | Spring Context 重启 / 应用重启 | ✅ 是(可通过反射移除 |
| Java Agent | JVM 启动时加载 或 attach 注入成功 | 持续 Hook 字节码,独立于 Web 层 | JVM 进程终止 | ❌ 否 |
| Tomcat Valve | 注入到 Container Pipeline 成功 | 在 Connector 层持续生效,早于 Filter | Tomcat Server 重启 | ❌ 否(需重启 Server) |
| MBean | registerMBean() 成功 |
持续驻留 MBeanServer,可被远程调用 | 手动 unregister / JVM 重启 | ✅ 是(可手动注销) |
内存马生命周期流程图

利用前提¶
内存马的注入实际上就是执行Java代码。所以内存马利用的必要前提条件就是能够在web应用的上下文执行Java代码。
通常通过以下方式:
| 入口类型 | 说明 | 示例 |
|---|---|---|
| 1. JSP Webshell | 上传或写入一个 JSP 文件,内含 Java 代码 | <% Runtime.getRuntime().exec(request.getParameter("cmd")); %> |
| 2. 反序列化漏洞 | 利用 Java 反序列化漏洞(如 Commons-Collections、Fastjson、Jackson)执行代码 | Fastjson @type 指定恶意类,触发构造器或 getter |
| 3. 表达式注入 | 利用 EL 表达式、SpEL、OGNL、MVEL 等执行动态代码 | Spring SpEL:T(java.lang.Runtime).getRuntime().exec("whoami") |
| 4. 文件上传 + 目录穿越/解析漏洞 | 上传 JSP 文件到可执行目录 | 上传 shell.jsp 到 /webapps/ROOT/ |
| 5. 框架 RCE 漏洞 | 如 Struts2、Spring Cloud、Shiro、Log4j2 等框架漏洞 | Log4j2 JNDI 注入 → 加载远程恶意类 |
| 6. 管理后台 / 调试接口 | 如 Spring Boot Actuator、Druid 监控、Swagger 未授权 | /actuator/ + env + restart + 自定义注入 |
| 7. 服务器命令执行 → 写入 JSP | 通过其他漏洞(如 PHP、Python RCE)写入 JSP 文件 | 服务器存在 Python RCE → echo '<%...%>' > /tomcat/webapps/ROOT/shell.jsp |
| 8. Java Agent 附加(高阶) | 通过 VirtualMachine.attach(pid) 注入 Agent(需本地权限) |
利用本地漏洞或运维权限 attach 到 Tomcat 进程 |
内存马原理¶
Servlet-api类¶
在 Java Web 开发中,Servlet、Filter 和 Controller 是三个核心组件
客户端请求
↓
Filter(如 CharacterEncodingFilter、CorsFilter 等)
↓
DispatcherServlet(继承自 HttpServlet,是前端控制器)
↓
HandlerMapping → 找到对应的 @Controller
↓
Controller 方法执行(调用 Service、返回 ModelAndView 或 JSON)
↓
返回响应(经过 Filter 的 response 后处理)
- Filter 像是“安检门”:检查每个人(请求)是否携带违禁品(非法参数、未登录等),决定是否放行。
- DispatcherServlet 像是“前台接待”:接收所有来访者,根据需求(URL)分配到对应部门(Controller)。
- Controller 像是“业务专员”:具体处理客户的需求(业务逻辑)。
Filter 内存马¶
- **挂载点:**Servlet
Filter链(例如:Tomcat 的ApplicationFilterChain)。 - **原理:**攻击者通过反射在运行时向
FilterChain动态注册一个恶意的javax.servlet.Filter实例。由于 Filter 位于请求处理的最前端,它能**在请求到达目标 Servlet/Controller 之前**拦截所有或特定 URL 的请求。 - **企业级危害:极具威胁。**Filter 内存马可以实现前置身份验证绕过、会话劫持、敏感数据过滤(例如,拦截信用卡号或密码)、WebShell 命令执行。它位于请求处理的最上层,几乎可以影响所有传入流量。
Servlet内存马¶
- **挂载点:**Servlet 容器 (
ServletContext)。 - **原理:**攻击者通过
ServletContext的 API(如addServlet),动态注册一个恶意的javax.servlet.Servlet。这个恶意 Servlet 可以绑定到一个特定的 URL 路径,从而创建新的、隐蔽的后门路由。 - **企业级危害:**能够创建全新的、不显眼的访问路径,实现远程命令执行、文件上传/下载等功能。由于其不依赖现有业务逻辑,仅需知道新的 URL 路径即可访问,隐蔽性较强。
Listener内存马¶
- 挂载点:
ServletContextListener、ServletRequestListener等监听器。 - **原理:**攻击者注册一个恶意的
Listener,利用其在特定生命周期事件(如应用启动、请求初始化、会话创建/销毁等)触发的特性来执行恶意逻辑。 - 企业级危害:持久性较好。特别是
ServletContextListener,它可以在应用启动时执行初始化恶意代码,甚至植入其他内存马。ServletRequestListener则可用于对每个请求进行监控或修改。
Spring类¶
Spring Controller 内存马¶
- **挂载点:**Spring MVC
Controller(通过RequestMappingHandlerMapping)。 - **原理:**对于 Spring MVC 应用,攻击者通过反射操作 Spring 框架的核心组件
RequestMappingHandlerMapping,动态注册一个恶意ControllerBean。这使得攻击者可以为恶意功能注册一个全新的 URL 路由,使其看起来就像应用中合法的接口。 - 企业级危害:高度针对 Spring 应用,能够无缝融入 Spring 路由体系,创建隐蔽的后门 API 接口,实现远程命令执行、WebShell 等功能,难以通过传统代码审计发现。
spring intercetor 内存马¶
- 挂载点:Spring MVC Interceptor(通过
RequestMappingHandlerMapping的adaptedInterceptors字段)。 - 原理:对于 Spring MVC 应用,攻击者通过反射获取 Spring 上下文中的
RequestMappingHandlerMapping实例,并修改其父类AbstractHandlerMapping中的adaptedInterceptors列表,动态插入一个恶意的HandlerInterceptor实现。该拦截器可在请求处理的preHandle阶段执行任意代码(如命令执行、回显 WebShell 等),且对所有经由 Spring MVC 路由的请求生效,无需新增 URL 路径。 - 企业级危害:高度适配 Spring 应用架构,无需修改磁盘文件或注册新接口,隐蔽性强;恶意逻辑嵌入在正常请求流程中,可绕过基于 URL 白名单或接口审计的安全检测,实现持久化、低感知的远程控制,对传统 WAF 和代码审计工具具有极强的绕过能力。
Tomcat Valve 内存马¶
- 挂载点:Tomcat Pipeline
Valve。 - 原理:
Valve是 Tomcat 请求处理管道中的核心组件,每个请求在到达目标 Servlet 之前都会经过一系列的Valve。攻击者通过反射将自定义的恶意Valve动态加入到 Tomcat 的Pipeline中,从而在所有请求处理的前后插入恶意逻辑。 - 企业级危害:影响范围广且隐蔽性强,能够全局拦截和处理 Tomcat 接收到的所有请求,比 Filter 更底层。可以实现通用性的数据窃取、流量劫持或命令执行。
MBean 内存马¶
- 挂载点:JMX MBean。
- 原理:Java Management Extensions (JMX) 允许对 Java 应用程序进行管理和监控。攻击者可以注册恶意的
MBean,并通过 JMX 远程调用这些MBean中定义的方法,从而实现远程代码执行 (RCE) 或其他恶意操作。 - 企业级危害:如果 JMX 端口暴露或存在弱认证,攻击者可以直接通过 JMX 远程管理协议触发内存马,实现高度隐蔽的 RCE,尤其是在管理工具或监控系统中可能被忽视。
Agent 内存马¶
- **挂载点:**JVM Instrumentation API /
sun.misc.UnsafeAPI。 - **原理:**这是最复杂也最强大的内存马类型。攻击者利用 Java Agent 或
sun.misc.Unsafe等底层 API,动态修改或替换已加载类的字节码。例如,Hook 关键的安全检查方法、数据库操作方法或命令执行方法,直接在程序核心逻辑中植入后门。 - 企业级危害:极难检测,隐蔽性最高。它直接篡改 JVM 内部运行的类,可以绕过大多数应用层面的检测,实现深度持久化,甚至可以劫持类加载过程,阻碍后续的修复和检测。
总结¶
各内存马执行顺序¶
[容器层]
Tomcat Valve 内存马
- 执行时机:最早,在请求进入 Web 应用前就已执行
- 可拦截所有请求(包括未映射路径、静态资源)
- 绕过 Web 应用层所有安全机制
[Web 应用层]
- ServletContextListener内存马,web应用启动时(不参与http)
- HttpSessionListener内存马(可前可后,取决于何时调用 getSession()
// 在 Filter 中调用 getSession() → 触发 sessionCreated() 则执行在filter中
// 在 Controller 中调用 getSession() → 同样触发,但已在 Filter 之后
- ServletRequestListener内存马
ServletRequestListener.requestInitialized()在filter之前
- Filter 内存马
[Servlet 层]
Servlet内存马
[Spring MVC 层]
- Spring Interceptor 内存马(preHandle)
- Spring Controller 内存马(@RequestMapping 方法)
[响应返回]
请求的逆序
使用场景分类¶
| 场景 | 推荐内存马类型 | 理由 |
|---|---|---|
| 快速上线、通用兼容 | Filter | 无需框架、全局拦截、代码简单、清除需重部署 |
| 长期潜伏、对抗清除 | Listener + Filter | Listener 可监听 Context 重启并重新注入 Filter |
| 高权限、深度隐藏 | Tomcat Valve | 在 Filter 之前执行,日志/监控常忽略 |
| 绕过 RASP/Spring | Java Agent | 不经过 Web 层,直接 Hook,RASP 无法拦截 |
| 远程管理、后渗透 | MBean | 可通过 JConsole / JMX 远程执行,适合内网横向 |
| Spring 环境快速利用 | Spring Controller | 无需反射,直接注入 HandlerMapping,但易被刷新 |
| Spring 环境隐蔽持久化 | Spring Interceptor | 深度集成 Spring MVC,可记录/篡改请求响应,比 Controller 更隐蔽,且不易被业务日志发现 |
提高隐蔽性总体方向¶
- 路径/参数/文件名无敏感词
- 自定义 Header/json传参
- 请求参数和返回值编码
- dnslog等外带
- 响应伪装成正常业务(状态码、Content-Type、Body、json,静态资源、业务路径)
- 不打印日志、不抛异常
- 敏感字符串运行时拼接
终极原则:让流量看起来像正常用户,让内存看起来像正常框架,让文件系统无痕迹。
防御¶
内存马需要能执行Java代码,通过防御webshell如上传jsp、反序列化漏洞等就能使内存马无法注入。
| 内存马类型 | 防御手段 |
|---|---|
| Filter / Servlet / Listener | 监控 ServletContext.addXxx() 调用;启用 SecurityManager;部署后禁止动态注册 |
| Spring Controller | 禁用 Actuator /refresh;监控 RequestMappingHandlerMapping 修改 |
| Spring Interceptor | 监控 HandlerMapping 的 interceptorList / adaptedInterceptors 字段变更;限制反射访问 Spring 内部类;启用运行时字节码审计(如 RASP) |
| Java Agent | 禁止 -javaagent 参数;限制 attach 权限;使用 JVMTI 监控 |
| Tomcat Valve | 审计 server.xml;监控 StandardEngine/Host/Pipeline 反射调用 |
| MBean | 关闭不必要的 JMX 端口;启用 JMX 认证;监控 MBeanServer.registerMBean |