跳转至

内存马分析

Java内存马原理与利用

内存马简介

内存马是webshell的一种,不同于文件马,内存马无文件落地。顾名思义,内存马将恶意逻辑直接注入到目标 Java Web 应用程序的运行时内存中。内存马可以绕过文件监测系统,不易被定位和监控。在绕过安全设备和实现持久化控制上优于传统文件马。

Java内存马分类

按挂载点不同分为以下:

  1. Servlet-api类
Text Only
Filter内存马
Servlet内存马
Listener内存马
  1. Spring类
Text Only
Spring Controller 内存马
spring intercetor 内存马
  1. Tomcat Valve 内存马

  2. MBean 内存马

  3. Agent 内存马

1757864224727-a7f4ab95-19cf-4ef8-8678-2e3d47952c18

内存马的生命周期

内存马的生命周期与 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 是三个核心组件

Text Only
客户端请求
    ↓
Filter(如 CharacterEncodingFilter、CorsFilter 等)
    ↓
DispatcherServlet(继承自 HttpServlet,是前端控制器)
    ↓
HandlerMapping → 找到对应的 @Controller
    ↓
Controller 方法执行(调用 Service、返回 ModelAndView 或 JSON)
    ↓
返回响应(经过 Filter 的 response 后处理)
  • Filter 像是“安检门”:检查每个人(请求)是否携带违禁品(非法参数、未登录等),决定是否放行。
  • DispatcherServlet 像是“前台接待”:接收所有来访者,根据需求(URL)分配到对应部门(Controller)。
  • Controller 像是“业务专员”:具体处理客户的需求(业务逻辑)。
Filter 内存马
  • **挂载点:**ServletFilter链(例如: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 MVCController(通过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 PipelineValve。
  • 原理: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 应用层]

  1. ServletContextListener内存马,web应用启动时(不参与http)
  2. HttpSessionListener内存马(可前可后,取决于何时调用 getSession()
Text Only
// 在 Filter 中调用 getSession() → 触发 sessionCreated() 则执行在filter中
// 在 Controller 中调用 getSession() → 同样触发,但已在 Filter 之后
  1. ServletRequestListener内存马

ServletRequestListener.requestInitialized()在filter之前

  1. Filter 内存马

[Servlet 层]

Servlet内存马


[Spring MVC 层]

  1. Spring Interceptor 内存马(preHandle)
  2. 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

参考文章

Java内存马原理及利用 - J_0k3r