FEATURED · 精选文章

Java内存马检测实战:从原理到排查的完整安全指南

发布时间 / 2026/8/2 17:02:23
来源 / 创域科博编辑部
栏目 / 资讯中心
Java内存马检测实战:从原理到排查的完整安全指南 1. 项目概述为什么内存马成了安全运维的“心头大患”在安全攻防的战场上攻击手段的演进速度总是快得让人心惊。几年前大家还在为Webshell上传、SQL注入这些传统攻击方式忙得焦头烂额各种WAF、IDS规则也堆得密密麻麻。但不知从何时起一种更隐蔽、更顽固的威胁悄然流行起来——内存马。它不像传统的木马文件那样会留下一个实实在在的.jsp或.php文件在服务器的硬盘上等着你去扫描、删除。内存马顾名思义它只存在于服务器的内存RAM中。攻击者利用应用程序运行时的一些机制比如Java的Filter、Servlet或者Spring的Controller、Interceptor将恶意代码动态注入到正在运行的进程里。服务器一重启这些恶意代码就随着内存释放而烟消云散但攻击载荷却能在运行时持续生效接收远程指令执行任意命令。这种“无文件”的攻击方式让传统的基于文件特征和静态扫描的检测手段几乎失效。你很难通过查看web目录来发现它常规的杀毒软件也常常对它视而不见。它就像潜伏在系统血管里的“幽灵”直接与业务应用共生权限高、隐蔽性强。我遇到过不少案例应急响应团队在服务器上翻了个底朝天文件日志、网络连接都查遍了就是找不到攻击入口最后才发现是某个不起眼的Web应用被注入了内存马成了攻击者的持久化后门。因此掌握一套行之有效的内存马检测与排查手段对于任何负责系统安全、应用运维或应急响应的工程师来说已经从“加分项”变成了“必备技能”。这不仅仅是技术层面的对抗更是一场关于对系统运行时状态理解深度的较量。2. 内存马的核心原理与分类知己知彼百战不殆要有效检测必须先深入理解对手。内存马并非一种单一的技术而是一类攻击技术的统称其核心思想是“在应用程序的运行时内存中动态注册一个恶意的处理单元”。这个单元能够拦截、处理特定的网络请求通常是HTTP请求并执行攻击者下发的指令。2.1 内存马的工作原理链条一个典型的内存马攻击链通常包含以下几个环节漏洞利用攻击者首先需要找到一个入口点。这可能是Web应用的一个远程代码执行漏洞RCE比如Fastjson、Log4j2、Shiro的反序列化漏洞也可能是通过上传漏洞传了一个包含注入代码的“种子”文件。代码注入利用漏洞攻击者将一段精心构造的代码片段Payload发送到目标服务器。这段代码的核心功能是向当前运行的Web容器如Tomcat、Jetty、Spring Boot内嵌容器或应用框架如Spring动态注册一个新的组件。组件注册注入的代码会利用Java的反射机制、JNDI注入、或框架自身的扩展点向容器注册一个恶意的Filter、Servlet、Controller、Interceptor或者Valve。这个恶意组件会被绑定到一个特定的URL路径例如/favicon、/api/test等看起来正常的路径。后门建立注册成功后当外部请求访问这个特定的URL路径时请求就会被这个恶意组件接管。该组件会解析请求中的参数可能经过加密或编码在内存中执行对应的系统命令如whoami、ipconfig、cat /etc/passwd并将执行结果返回给攻击者。整个过程完全在内存中完成不落盘。2.2 常见内存马类型详解根据注入的目标和利用的技术不同内存马主要分为以下几类每种都有其特点和检测难点2.2.1 Servlet-API型内存马这是最经典的类型主要针对Servlet容器Tomcat、Jetty等。Filter型内存马这是最常见的一种。Filter是Servlet规范中的过滤器可以拦截请求和响应。恶意Filter被动态添加到过滤器链的首位可以拦截所有请求。由于其优先级高甚至可以在业务代码执行前就完成攻击动作并返回响应极其隐蔽。Servlet型内存马动态注册一个恶意的Servlet到容器的上下文Context中。当访问其映射的URL时触发。Listener型内存马相对少见通过注册特定事件如ServletRequestListener的监听器在请求生命周期特定阶段执行恶意代码。2.2.2 Spring框架型内存马随着Spring生态的普及针对Spring的内存马也越来越多。Controller型内存马利用Spring MVC的机制动态向RequestMappingHandlerMapping注册一个恶意的Controller。这种内存马看起来就像一个正常的API接口在Spring的监控和管理界面中可能都难以区分。Interceptor型内存马动态注册一个HandlerInterceptor其作用和Filter类似但属于Spring MVC层面可以拦截进入Controller的请求。Spring Bean型内存马更底层的注入方式直接向Spring的ApplicationContext中注入一个恶意的Bean这个Bean可能被用于各种依赖注入场景危害面更广。2.2.3 其他中间件/框架型内存马WebSocket内存马在支持WebSocket的应用中注册恶意端点Endpoint通过WebSocket通道进行隐蔽通信。JSP内存马严格来说这不算纯内存马因为JSP文件最终需要落盘编译。但有一种变种是将恶意JSP的内容直接写入内存中的类加载器如org.apache.catalina.loader.WebappClassLoader的resourceEntries缓存实现“不落盘”的JSP执行。注意理解这些类型的关键在于抓住它们的共同点——动态修改运行时内存中的程序结构。无论是Filter、Servlet还是Controller在正常部署时它们的定义都来自磁盘上的类文件或配置。而内存马绕过了这个环节直接操作内存中的对象和映射关系。3. 检测思路与技术体系从“盲人摸象”到“全景扫描”面对内存马这种“隐形”威胁单一的检测方法很容易失效。我们需要建立一个多层次、立体化的检测技术体系。这个体系可以从三个维度展开行为监控、内存分析和流量分析。3.1 行为监控寻找“异常”的蛛丝马迹内存马要工作必然会产生不同于正常应用的行为特征。这是检测的第一道防线。3.1.1 进程与网络连接监控可疑网络连接内存马需要与攻击者控制端C2通信。使用netstat -antp或ss -antp命令重点排查服务器上是否存在到异常外网IP或域名的长期ESTABLISHED连接尤其是业务应用Java进程发起的连接。一些内存马会使用HTTP/HTTPS协议伪装成正常的API调用但频率、数据包大小、访问时间可能异常。进程行为异常监控Java进程是否在非业务时段有异常的CPU或内存使用高峰或者是否执行了Runtime.exec()调用。可以通过jstack查看线程栈寻找执行命令的线程通常线程名可能包含http-、exec等但攻击者也会伪装。3.1.2 应用内部组件审计这是检测的核心因为内存马的本质是增加了额外的程序组件。动态查询Servlet/Filter映射对于Tomcat可以通过JMX接口或管理Servlet如果开启且安全动态获取当前Context中所有注册的Servlet和Filter及其URL映射。编写脚本定期拉取这份列表与基线如应用启动时的列表、项目标准配置web.xml或WebFilter注解声明的列表进行对比任何“多出来”的映射都值得高度怀疑。Spring MVC映射审计对于Spring Boot应用可以通过访问/actuator/mappings端点需开启获取所有Controller的映射信息。同样与已知的业务接口列表进行比对。也可以编程方式从Spring的RequestMappingHandlerMappingbean中获取所有HandlerMapping信息进行检查。3.2 内存分析直击“幽灵”的藏身之处既然马在内存里最直接的证据自然也就在内存里。Java内存分析是一门深奥的技术但在内存马检测中我们可以聚焦于几个关键对象。3.2.1 核心分析目标ClassLoader与加载的类检查是否有未知来源的类被加载。特别关注URLClassLoader、BCEL ClassLoader等可能用于动态加载恶意类的加载器。Servlet容器核心对象StandardContextTomcat中Web应用的上下文对象其中包含了filterDefsFilter定义、filterConfigsFilter配置、filterMapsFilter映射以及servletMappings等关键属性。恶意组件必然在这里留下痕迹。ApplicationFilterChain过滤器链对象内存马Filter为了优先执行通常会将自己插入到链的头部。Spring框架核心对象RequestMappingHandlerMapping保存了所有URL到Controller方法的映射关系。AbstractHandlerMethodMapping.MappingRegistry内部维护映射注册表。ApplicationContext所有的Spring Bean都在这里管理。3.2.2 分析工具与方法JDK自带工具jmap -dump:live,formatb,fileheap.hprof可以导出Java堆内存快照。然后使用专业的分析工具如Eclipse MAT, JProfiler加载快照进行分析。在MAT中你可以通过OQL对象查询语言来搜索特定的类名、URL模式或分析对象引用关系。例如在MAT的OQL控制台中输入SELECT * FROM org.apache.catalina.core.StandardContext来查找所有的StandardContext实例。Java Agent技术这是更高级、更实时的检测方式。通过编写一个Java Agent在JVM启动时或运行时附着Attach到目标进程利用Instrumentation API来动态地监控类的加载、修改类的字节码或者直接遍历JVM中的对象图。许多专业的内存马检测工具如后面会提到的底层都依赖此技术。它可以无侵入地获取到内存中最真实的状态。3.3 流量分析捕捉“通信”的异常脉搏内存马终究需要一个“遥控器”。分析进出应用的网络流量往往能发现决定性证据。3.3.1 HTTP流量特征URL路径异常内存马使用的路径可能比较奇怪如/favicon、/static/..;/api利用路径穿越、/xxx.css伪装静态资源等或者路径长度、参数名异常。请求参数与响应特征攻击载荷可能经过Base64、Hex、AES等加密编码。观察请求体Body是否携带大段的、看似乱码的数据。响应体可能不是标准的JSON/HTML而是命令执行结果的直接输出如root等系统用户名。请求头Header异常攻击者可能在Cookie、User-Agent、自定义Header中传递指令。访问频率与时间在业务低峰期如深夜出现规律性的、固定路径的访问。3.3.2 分析工具应用层日志仔细审查Web容器的访问日志如Tomcat的localhost_access_log.*.txt寻找上述可疑的请求记录。网络抓包在怀疑的服务器上使用tcpdump抓取应用端口如8080的流量然后用Wireshark进行分析。可以设置过滤条件只关注特定IP或包含可疑字符串的流量。RASP/Web防火墙部署具有自学习能力的RASP运行时应用自我保护或下一代WAF它们可以建立正常的流量模型并对偏离模型的异常请求进行告警对加密流量也有一定的解码和分析能力。4. 实战排查流程一套可落地的“组合拳”理论讲再多不如一次实战。下面我结合一次真实的应急响应案例梳理出一套标准化的排查流程。假设我们收到告警某台业务服务器的CPU在夜间异常飙升怀疑被入侵。4.1 第一阶段快速初步筛查与遏制目标是快速确认是否存在恶意活动并尽可能阻止损害扩大。隔离与快照立即将可疑服务器从负载均衡池中摘除限制其网络访问只保留管理通道。如果条件允许对服务器制作一个虚拟机快照或创建镜像为后续的深度取证保留现场。这是最重要的一步避免在排查过程中打草惊蛇或导致攻击者销毁证据。检查网络连接快速登录服务器执行netstat -antp | grep ESTABLISHED或ss -antp state established。重点关注Java进程通过PID识别是否与不常见的外网IP建立了连接。记录下所有可疑的远端IP和端口。检查进程与资源使用top或htop命令查看是哪个进程消耗CPU高。如果是Java进程使用ps aux | grep java查看其启动命令和参数有无异常。检查近期日志快速查看Web应用日志如Spring Boot的application.log、系统日志/var/log/messages,journalctl -xe以及Web容器访问日志寻找在CPU飙升时间点前后的异常错误信息或访问记录。4.2 第二阶段深度内存与组件分析如果初步筛查发现疑点就需要进行更深入的、针对内存马的专业分析。4.2.1 使用专业工具进行内存扫描手动分析内存快照门槛很高幸运的是现在有一些优秀的开源工具可以辅助我们。Arthas阿尔萨斯阿里开源的Java诊断神器非常适合在线排查。它通过Attach机制连接到Java进程无需重启。安装与连接直接下载arthas-boot.jar运行java -jar arthas-boot.jar选择目标Java进程PID。关键命令sc -d *Filter搜索所有已加载的Filter类查看其类加载器和来源Jar包。重点关注非项目依赖包中的Filter。sc -d *Servlet同上搜索Servlet。jad com.example.MaliciousFilter如果发现可疑类可以用jad命令反编译它的字节码直接查看源代码逻辑这是最直接的证据。tt -t org.apache.catalina.core.ApplicationFilterChain doFilter监听过滤器链的doFilter方法调用可以看到每个请求经过的Filter顺序和类名能直接发现插入在链首的恶意Filter。ognl命令可以执行OGNL表达式直接查询Spring容器的Bean。例如获取所有的Controller映射ognl #springContextcom.xxx.ApplicationContextProvidercontext, #springContext.getBean(requestMappingHandlerMapping).getHandlerMethods()需要根据实际环境调整。Java-MemoryShell-Backdoor-DetectionGitHub上一些专注于内存马检测的项目它们通常打包成一个JAR通过Java Agent注入到目标进程自动遍历和分析内存中的Servlet、Filter、Controller等组件并与基线对比生成报告。使用前需在测试环境验证避免对生产环境造成影响。手动Dump与分析如果工具受限使用jmap -dump导出堆快照然后用Eclipse MAT分析。在MAT中打开直方图Histogram按类名排序搜索Filter,Servlet,Controller,Handler等关键词。找到可疑类后右键选择List objects - with incoming references查看谁引用了它通常可以追溯到StandardContext或ApplicationContext。使用OQL查询例如查找所有Filter定义SELECT * FROM org.apache.catalina.deploy.FilterDef。4.2.2 对比分析与基线确认工具给出的可疑列表需要人工复核。你需要一份该应用正常的“组件基线”。如何建立基线在应用安全启动后立即使用上述工具如Arthas导出一份完整的Servlet/Filter/Controller映射列表并归档保存。这份列表应该与你的项目代码和配置web.xml,WebFilter,RequestMapping能对应上。对比分析将实时获取的列表与基线对比。任何新增的、来源jar包不明确的特别是来自Tomcat/lib、JVM启动参数中-javaagent指定的jar或者内存中动态生成的类、映射路径奇怪的组件都需要重点审查。4.3 第三阶段漏洞定位与清除修复发现内存马后工作只完成了一半更重要的是找到根源并彻底清理。定位注入点内存马不是凭空产生的。回顾排查时间线检查在内存马可能被注入的时间点前后应用日志中是否有异常报错如反序列化错误、表达式解析错误。检查是否有相关的漏洞利用尝试记录。这可能是未修复的漏洞也可能是弱口令、配置不当导致的管理后台被入侵。清除内存马治标 - 重启服务最简单彻底的方法是重启Java应用。内存马随进程消亡而消失。但务必在重启前修复漏洞入口否则攻击者可能很快再次注入。治标 - 动态卸载对于Tomcat可以通过编程方式或JMX从StandardContext的filterDefs、filterConfigs、filterMaps等集合中移除恶意组件。对于Spring可以从HandlerMapping中移除恶意映射。这种方法技术要求高且可能因版本差异而操作不同风险较大仅适用于紧急临时处置。修复与加固修复漏洞根据定位到的注入点升级框架、组件版本修补安全漏洞。清理后门文件检查服务器上是否存在攻击者上传的用于注入的“种子”文件如特殊的JSP、Jar包等彻底删除。修改口令重置所有相关系统的管理口令、数据库连接口令等。应用加固考虑部署RASP进行运行时保护限制Java进程执行高危系统命令的能力通过SecurityManager或Agent拦截对Web应用进行定期的组件清点和漏洞扫描。5. 高级技巧与疑难问题排查在实际对抗中攻击者的技术也在升级会采用更多规避手段。这里分享一些应对高级内存马和疑难情况的技巧。5.1 对抗反检测技术一些高级内存马会尝试隐藏自己类名随机化每次注入生成随机的类名避免被字符串匹配发现。应对关注类行为而非类名。通过Arthas的tt命令监听Filter.doFilter或Controller方法调用观察其参数和返回值逻辑是否异常。模仿正常组件将恶意Filter命名为NormalFilter插入到过滤器链的中间而非头部。应对依赖基线对比即使名字正常只要不在基线列表中就是可疑的。同时检查Filter的顺序是否被篡改。使用字节码技术直接修改已加载的正常类的字节码在其中插入恶意逻辑如“冰蝎”内存马。这种检测难度极大。应对可以使用Java Agent进行类的字节码校验对比磁盘上的class文件与内存中已加载的类文件的MD5值是否一致。一些RASP产品具备此功能。5.2 排查中的常见“坑点”误报应用本身使用了动态注册组件的技术例如某些中间件热部署功能、某些监控Agent如SkyWalking的Java Agent也会注册Filter。这需要结合组件的来源是否来自可信的官方Jar包和功能进行判断。环境差异基线环境与生产环境不一致如依赖版本不同、配置不同导致对比出现大量“差异”干扰判断。因此基线最好在类生产环境的Staging环境中获取。工具影响某些内存分析工具特别是基于Agent的本身会向目标JVM注入类可能会被误判。使用多个工具交叉验证并了解工具本身的原理。重启失效的“顽固”马极少数情况下攻击者可能通过修改持久化配置如context.xml、感染公共库如tomcat/lib下的jar或利用JVM启动参数使得重启后内存马被再次加载。排查时需检查这些持久化位置。5.3 构建常态化检测体系应急响应是被动的主动防御才是上策。定期组件清点编写脚本定期如每天通过JMX或管理接口获取线上所有应用的组件映射列表与黄金基线进行自动化比对发现差异立即告警。部署RASP在关键应用上部署运行时应用自我保护系统。好的RASP能够监控所有敏感操作如文件读写、命令执行、网络连接、反射调用等并基于行为模型进行阻断能从根源上防御大部分内存马注入。加强漏洞管理建立严格的软件成分分析SCA和漏洞扫描流程及时修复第三方依赖中的已知漏洞堵住最常见的攻击入口。最小权限原则运行Java应用的系统用户应遵循最小权限原则避免使用root权限。限制Java进程的网络出站连接通过防火墙策略只允许访问必要的内部服务切断内存马的回连通道。内存马的攻防是一场关于深度的较量。它迫使安全人员和运维人员必须超越对配置文件和日志的依赖去深入理解应用的运行时状态、JVM的内存模型和容器的核心机制。这套排查手段与其说是一套工具集不如说是一种新的问题排查思路。它要求我们像法医一样在系统的“活体”中寻找犯罪的痕迹。掌握它不仅能解决内存马的问题更能极大地提升你对Java应用、对系统运行时状态的整体把控能力。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻