第106篇AI全栈·应急响应——全类型JAVA内存马排查"

admin 2026-10-22 13:26:46 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

第106篇 AI全栈 · 应急响应——全类型JAVA内存马排查

原创

陈看山
陈看山

安全诸子

2026年10月19日 12:35
浙江

去阅读

应急场景里最怕的不是看到告警,而是告警亮了、流量侧已经出现密集的冰蝎或哥斯拉指纹,但你在目标主机上翻遍了临时目录、上传目录、web 目录,找不到任何 webshell 文件。这个时候基本可以判断是内存马,但判断是判断,怎么把它从 JVM 里揪出来,是另一回事。 这篇文章不重复内存马的实现原理,也不贴攻击代码,而是从防守方的应急视角,给你一套可以直接拿去用的全类型 JAVA 内存马排查作战流程。基于当前可见信息,来源原文主要覆盖了 Tomcat 环境下 Servlet、Filter、Listener 三类动态注册组件型内存马,以及 Java Agent 型内存马的排查思路。这套流程在多数企业级应急场景里足够用了。

排查前先搞清楚

你要对抗的是什么 Java web 应用接管请求处理逻辑,本质上只有两条路:一是直接修改 JVM 里已存在的处理类字节码,二是利用 web 容器自身的扩展机制,动态添加新的处理组件。对应到内存马,就是三类: - 基于动态注册 Servlet 组件(Servlet、Filter、Listener)的内存马:攻击者拿到代码执行权限后,通过反射拿到 StandardContext,往里 add 一个恶意 Filter 或 Servlet,逻辑直接写在匿名内部类里,不落地任何 class 文件。 - 基于框架组件(Spring、Struts2 等)的内存马:思路类似,利用框架自身的注册机制挂载拦截器或 Controller。 - 基于 Java Agent 的内存马:通过 attach 机制挂 agent,用字节码改写工具修改关键处理类的字节码,比如在 javax.servlet.http.HttpServlet.service() 或某个业务父类的方法入口插入恶意逻辑。 这三类在排查时的难点完全不同。第一类相对好查,因为组件列表是公开的,你只要能拿到容器上下文,就能遍历出所有实例。第二类要看你是否熟悉框架的 bean 注册结构。第三类最难,因为它是在类加载层面动的手脚,常规的组件遍历看不到它,只能靠字节码层面去审计。

排查流程的输入、输出与角色定义 在写具体步骤前,先把流程的边界定义清楚,这决定了你后面每一步的动作是否有效

  • 输入:被入侵主机的进程 PID,JVM 运行环境(JDK 版本、是否容器化),web 容器类型(Tomcat、Spring Boot 内嵌 Tomcat、Jetty),已知的攻击入口 URL 或漏洞接口(如果有),流量侧的内存马连接指纹(冰蝎、哥斯拉等)。 - 输出:确认是否存在内存马,定位到具体类名、实例名、classloader 层级,提取恶意类字节码,给出清除建议(重启或热卸载)。 - 参与角色:应急响应人员(主操作)、安全运营(提供流量告警上下文)、应用运维(提供应用部署信息和重启窗口)。 - 约束条件:线上业务不能随便重启,生产环境可能没有 arthas 等诊断工具,目标 JVM 可能处于高负载状态,attach 操作本身有风险。 这些约束决定了你不能上来就瞎试,而是要有优先级地推进排查。

排查执行阶段拆解

从粗筛到定位再到取证 整个排查过程我习惯拆成四个阶段,每个阶段都有明确的动作、判断点和产出物。

阶段一

信息收集与攻击面判断 先别急着连上服务器敲命令。先问自己几个问题:这个应用是什么框架?是传统 Tomcat 部署 war 包,还是 Spring Boot 内嵌容器?最近的代码执行漏洞入口在哪里?流量告警里内存马连接的特征 URL 是什么? 这些信息决定了你第一刀切在哪里。如果应用是纯 JSP 后台的 Tomcat,攻击者大概率是通过上传 JSP 触发代码执行,那么注入的内存马大概率是匿名内部类,外部类会在 org/apache/jsp/ 目录下留下痕迹。如果应用是 Spring Boot,攻击者更可能利用框架的组件注册机制。如果流量里出现了明显的哥斯拉 AES 加密流量,攻击者可能在 Filter 或 Interceptor 里做了路由映射。 这个阶段的产出物是一张信息表:应用类型、容器版本、JDK 版本、攻击入口、已知 payload 类型。有了这张表,后面的排查才有方向。

阶段二

组件实例粗筛——用 scanner JSP 快速定位三类内存马 如果是 Tomcat 环境,且你能在 web 目录下放一个 JSP 文件(或者通过已有漏洞执行 JSP 代码),c0ny1 师傅的 java-memshell-scanner 脚本是目前最快的粗筛工具。它的原理不复杂:通过反射拿到 org.apache.catalina.core.StandardContext,然后遍历其中的 servletMap、filterMap、listenerList 三个列表,把所有已注册的组件实例列出来。 判断标准很直接:正常业务组件的类名都是有意义的,比如 com.example.controller.UserServlet。如果你的列表里出现了类似 org.apache.jsp.servletmemshell\_jsp$1 这种匿名内部类,或者类名是一串无意义的随机字符串(比如 com.ax1z),基本可以列为重点怀疑对象。特别是 Filter 类型,看它的 Patern 字段,如果过滤路径是 /shell、/api/exec 这种明显不是业务路径的 URL,基本实锤。 这里有一个很多人忽略的细节:攻击者注入 Filter 型内存马时,通常会注册到 /\ 路径,因为这样所有请求都会经过它。如果你发现某个 Filter 的 mapping 是 /\,但类名又不是常见的框架安全过滤器(比如 Spring Security 的 springSecurityFilterChain),那就要仔细看它的实现逻辑。

阶段三

深度定位——用 Arthas 做类级审计 如果 scanner JSP 没有发现异常,或者你是 Spring Boot 内嵌容器没法放 JSP,那就需要上 Arthas attach 到目标 JVM。 Arthas 在这个场景下的核心价值不是反编译(它的 jad 功能其实比较弱),而是它能列出当前 JVM 加载的所有类,并且支持按接口、父类、类名模式过滤。三个命令先跑起来: bash # 查看所有类名中包含 servlet 的类 sc \Servlet\ # 按接口过滤,查找所有实现了 Filter 接口的类 sc -d \ --interfaces javax.servlet.Filter # 查找所有 ServletRequestListener 实现类 sc -d \ --interfaces javax.servlet.ServletRequestListener 注意 Arthas 默认只显示前 100 条结果,而且如果同一个类被多个 classloader 加载,会重复出现。所以建议先打开结果日志: bash options save-result true 然后去 {user.home}/logs/arthas-cache/result.log 里用正则过滤完整结果。 拿到可疑类名后,用 sc -d <类名> 获取它的 classloader hash,再用 jad 反编译看逻辑。对于 Servlet 型内存马,恶意逻辑一般在 service() 方法里;对于 Filter 型,一般在 doFilter() 里。重点看有没有 ProcessBuilder、Runtime.exec、defineClass、base64 解码等特征。 这个阶段的判断点在于:你找到的可疑类是否存在于本地 class 文件。如果 Arthas 里能查到类,但磁盘上对应的 class 文件不存在,或者类是从 com.sun.proxy.$Proxy 这种动态代理里生出来的,那基本可以断定是内存注入的产物。

阶段四

取证与清除 定位到可疑类后,用 Arthas 的 dump 命令把字节码导出来: bash dump <类名> 导出的 class 文件用 JD-GUI 或 FernFlower 反编译,作为应急处置报告的证据附件。清除手段分两种:如果确认是动态注册的 Filter/Servlet,可以通过反射调用 StandardContext 的 removeFilterMap、removeFilterDef 等方法卸载;如果是 Java Agent 型,理论上需要 remove 掉 agent 并 restore 被改写的字节码,但实际操作中成功率不高,稳妥的做法是业务低峰期重启应用。

不同排查手段的收益与代价对比 | 排查手段 | 适用场景 | 关键动作 | 产出物 | 风险点 | 优化建议 | |---------|---------|---------|--------|--------|---------| | scanner JSP 脚本 | Tomcat 外置容器,能执行 JSP | 遍历 StandardContext 三大组件列表 | 可疑组件实例清单 | JSP 落地可能触发安全监控,部分环境禁 JSP | 用后立即删除,或通过内存执行避免落地 | | Arthas 类检索 | 任意 JAVA 进程,生产可用 | sc 按接口/类名过滤 + jad 反编译 | 可疑类字节码与 classloader 关系 | attach 操作有性能开销,高负载 JVM 慎用 | 先 thread -n 3 看负载,低峰期操作 | | 流量侧反向定位 | 有 IDS/WAF 告警,知道内存马 URL | 用请求路径反查 Filter mapping | 攻击路径确认 | 流量加密(冰蝎 AES)时无法直接看 payload | 结合 JA3 指纹和连接频率做行为画像 | | 本地 class 文件比对 | 所有场景 | 检查 org/apache/jsp/ 下是否有 $ 匿名类文件 | 文件落地痕迹 | 攻击者可能注入后删除 class 文件 | 作为辅助手段,不能单独作为判断依据 |

实战中最容易翻车的三个环节

翻车点一

只查了 Filter,没查 Listener 很多应急人员知道 Filter 型内存马最常见,于是只盯着 sc \Filter\ 的结果看,忽略了 ServletRequestListener。Listener 型内存马在请求初始化时触发,隐蔽性比 Filter 更高,因为它的执行点在请求进入 Filter 链之前。排查时必须三条接口都查完,不能有遗漏。

翻车点二…


第106篇AI全栈·应急响应——全类型JAVA内存马排查" 网络安全文章

第106篇AI全栈·应急响应——全类型JAVA内存马排查"

这篇文章从防守方应急视角系统梳理了JAVA内存马排查流程,覆盖动态注册组件型与JavaAgent型内存马,提出四阶段排查法:信息收集、scannerJSP粗筛、Arthas深度定位、取证清除,并对比了不同排查手段的收益与代价,给出了实战中易翻车的环节与优化建议,具备较强可操作性。
19.2KStar!一份收录5000+插件的DeepSeekHarness生态精选列表" 网络安全文章

19.2KStar!一份收录5000+插件的DeepSeekHarness生态精选列表"

本文介绍开源项目AwesomeDSHPlugin,它收录了5000+个DeepSeekHarness生态插件,通过数据聚合和静态站点生成方式维护插件列表。项目亮点包括不排名只验证插件可用性、一插件一文件的管理方式,并提供AIAgent辅助查找插件的快速入门方法。该项目解决了插件数量过多时难以找到刚需插件的问题,其维护5000+社区目录的工程思路值得借鉴。
靶场实战11|报错也能把数据库拖走(附docker靶场部署步骤)" 网络安全文章

靶场实战11|报错也能把数据库拖走(附docker靶场部署步骤)"

本文实战演示MySQL报错注入攻击与防护。利用extractvalue/updatexml函数制造XPATH语法错误,使报错信息回显子查询结果,实现拖库。文章涵盖docker部署sqli-labs靶场、五步模拟攻击流程、WAF绕过三板斧(大小写混写、内联注释、空白替换)、日志攻击特征识别及防护措施。核心防护建议为参数化查询、关闭错误回显与最小权限账号。
评论:0   参与:  0