1. 1. Tomcat 与 Java Web 应急响应
  2. 2. 一、Tomcat 日志体系
    1. 2.1. 1.1 日志文件概览
    2. 2.2. 1.2 catalina.out 详解
    3. 2.3. 1.3 localhost_access_log 详解
    4. 2.4. 1.4 Manager 日志
    5. 2.5. 1.5 日志配置文件位置
  3. 3. 二、常见 Tomcat 入侵方式
    1. 3.1. 2.1 WAR 文件部署攻击
      1. 3.1.1. 攻击原理
      2. 3.1.2. 检测方法一:日志分析
      3. 3.1.3. 检测方法二:文件系统检查
      4. 3.1.4. Manager 弱密码检查
    2. 3.2. 2.2 JSP Webshell
      1. 3.2.1. 文件系统检测
      2. 3.2.2. 内容特征检测
      3. 3.2.3. 常见 JSP Webshell 代码特征
    3. 3.3. 2.3 AJP Ghostcat (CVE-2020-1938)
      1. 3.3.1. 漏洞概述
      2. 3.3.2. 检测方法
      3. 3.3.3. 修复方法
    4. 3.4. 2.4 反序列化攻击
      1. 3.4.1. 背景
      2. 3.4.2. 检测 classpath 中的危险库
      3. 3.4.3. 日志中的反序列化攻击痕迹
  4. 4. 三、内存马检测(重点)
    1. 4.1. 3.1 内存马与传统 Webshell 的区别
    2. 4.2. 3.2 基础检测:Java 进程分析
      1. 4.2.1. 定位 Java/Tomcat 进程
      2. 4.2.2. 线程 Dump 分析
      3. 4.2.3. 类加载信息分析
    3. 4.3. 3.3 内存马类型与对应检测方法
      1. 4.3.1. Servlet/Filter/Listener 型内存马检测
      2. 4.3.2. Spring Controller/Interceptor 型内存马检测
      3. 4.3.3. Agent 型内存马检测
    4. 4.4. 3.4 Arthas 实战检测
    5. 4.5. 3.5 内存 Dump 分析
  5. 5. 四、Tomcat 进程深度分析
    1. 5.1. 4.1 进程基础信息
    2. 5.2. 4.2 jstack 线程分析
    3. 5.3. 4.3 jcmd 综合诊断
    4. 5.4. 4.4 jmap 内存分析
  6. 6. 五、应急处置
    1. 6.1. 5.1 WAR Webshell 清理
    2. 6.2. 5.2 JSP Webshell 清理
    3. 6.3. 5.3 内存马清理
    4. 6.4. 5.4 Tomcat 安全加固
      1. 6.4.1. Manager 安全配置
      2. 6.4.2. AJP 加固
      3. 6.4.3. 运行权限
      4. 6.4.4. 移除不必要的应用
      5. 6.4.5. 隐藏版本信息
      6. 6.4.6. 配置安全头部
  7. 7. 六、实战练习
    1. 7.1. 6.1 实验环境
    2. 7.2. 6.2 练习一:WAR 部署攻击检测
    3. 7.3. 6.3 练习二:内存马检测
    4. 7.4. 6.4 练习三:综合应急
    5. 7.5. 6.5 思考题

Linux应急响应 - 11 Tomcat与Java-Web应急

Tomcat 与 Java Web 应急响应

作为 Java 生态中最广泛部署的 Web 容器,Tomcat 是攻击者重点关注的目标。Java Web 应急响应相比传统 Web 服务器(Nginx/Apache)有其独特之处:除了文件层面的 Webshell,还需要关注内存马(Memory Shell)这种无文件攻击方式。本章将从日志分析、入侵检测到应急处置,全面覆盖 Tomcat/Java Web 环境的应急响应技能。

本章特别关联你已有的内存马系列笔记,将攻击知识转化为防御视角的检测能力。

关联章节:

00-前置知识 — Java Web 基础架构

01-内存马概述 — 内存马分类与原理

02-Servlet型内存马 — Servlet/Filter/Listener 型内存马

03-Spring型内存马 — Spring Controller/Interceptor 型

06-检测与防御 — 检测与防御方法论

06-文件系统取证 — 文件系统分析

03-日志分析基础 — 日志分析通用方法

一、Tomcat 日志体系

1.1 日志文件概览

Tomcat 的日志体系比 Nginx/Apache 更复杂,涉及多个日志文件,各有不同用途:

日志文件 用途 应急分析价值
catalina.out Tomcat 主日志,包含 stdout/stderr 输出 — 异常堆栈、启动信息、部署操作
catalina.YYYY-MM-DD.log 按日期轮转的 catalina 日志 — 同上,历史记录
localhost_access_log.YYYY-MM-DD.txt HTTP 访问日志 — 攻击请求记录
localhost.YYYY-MM-DD.log Host 级别日志(Valve/Filter) — 应用部署、Filter 异常
manager.YYYY-MM-DD.log Manager 应用操作日志 — WAR 部署记录
host-manager.YYYY-MM-DD.log Host Manager 操作日志 — 虚拟主机管理

日志默认位置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 通过包管理器安装的 Tomcat
# Ubuntu/Debian
/var/log/tomcat9/ # Tomcat 9
/var/log/tomcat8/ # Tomcat 8

# CentOS/RHEL
/var/log/tomcat/

# 手动安装的 Tomcat(常见路径)
/opt/tomcat/logs/
/usr/local/tomcat/logs/
$CATALINA_HOME/logs/

# 快速定位 Tomcat 日志目录
ps aux | grep tomcat | grep -v grep | grep -oP 'catalina\.base=\K\S+'
# 或者
find / -name "catalina.out" 2>/dev/null

1.2 catalina.out 详解

catalina.out 是 Tomcat 最核心的日志文件,包含:

Tomcat 启动和停止信息

应用部署和卸载记录

应用抛出的异常堆栈

System.out.println()System.err.println() 的输出

关键日志模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 应用部署成功
INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/opt/tomcat/webapps/shell.war]
INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/opt/tomcat/webapps/shell.war] has finished in [1,234] ms

# 应用部署失败(可能是恶意 WAR 包含不兼容代码)
SEVERE [main] org.apache.catalina.startup.HostConfig.deployWAR Error deploying web application archive [/opt/tomcat/webapps/evil.war]

# 可疑的异常堆栈 — 反序列化攻击痕迹
java.io.InvalidClassException: filter status: REJECTED
java.lang.ClassNotFoundException: org.apache.commons.collections.functors.InvokerTransformer

# 可疑的命令执行堆栈
java.lang.Runtime.exec(Runtime.java:XXX)
java.lang.ProcessBuilder.start(ProcessBuilder.java:XXX)

应急分析命令:

1
2
3
4
5
6
7
8
9
10
11
# 搜索部署操作记录
grep -i "deploy\|undeploy\|Deploying" /opt/tomcat/logs/catalina.out

# 搜索异常和错误
grep -i "SEVERE\|ERROR\|Exception\|REJECTED" /opt/tomcat/logs/catalina.out | tail -100

# 搜索可疑的类加载(内存马可能涉及动态类加载)
grep -i "defineClass\|ClassLoader\|Transformer\|Instrumentation" /opt/tomcat/logs/catalina.out

# 搜索命令执行相关
grep -i "Runtime.exec\|ProcessBuilder\|cmd.exe\|/bin/bash\|/bin/sh" /opt/tomcat/logs/catalina.out

1.3 localhost_access_log 详解

访问日志格式(默认 combined 格式):

1
2
3
192.168.1.100 - - [15/Mar/2026:14:23:01 +0800] "GET /manager/html HTTP/1.1" 401 2345
192.168.1.100 - admin [15/Mar/2026:14:23:05 +0800] "GET /manager/html HTTP/1.1" 200 8765
10.0.0.50 - - [15/Mar/2026:14:25:00 +0800] "POST /app/upload HTTP/1.1" 200 45

字段解析:

192.168.1.100 — 客户端 IP

第一个 - — RFC 1413 ident(通常为空)

第二个 -admin — 认证用户名

[15/Mar/2026:14:23:01 +0800] — 请求时间

"GET /manager/html HTTP/1.1" — 请求方法、URI、协议

401 / 200 — HTTP 状态码

2345 — 响应字节数

日志格式配置位于 server.xml

1
2
3
4
5
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="localhost_access_log"
suffix=".txt"
pattern="%h %l %u %t &quot;%r&quot; %s %b" />

建议在应急前确认日志格式,不同配置的字段位置不同

1.4 Manager 日志

Tomcat Manager 是 WAR 部署攻击的核心入口,其日志记录了所有管理操作:

1
2
3
4
5
6
7
# Manager 认证尝试(记录在 localhost_access_log)
185.220.101.34 - - [15/Mar/2026:03:10:01 +0800] "GET /manager/html HTTP/1.1" 401 2345
185.220.101.34 - admin [15/Mar/2026:03:10:05 +0800] "GET /manager/html HTTP/1.1" 401 2345
185.220.101.34 - tomcat [15/Mar/2026:03:10:08 +0800] "GET /manager/html HTTP/1.1" 200 8765

# WAR 包部署操作
185.220.101.34 - tomcat [15/Mar/2026:03:11:00 +0800] "PUT /manager/text/deploy?path=/cmd&update=true HTTP/1.1" 200 123

关键分析点:

多次 401 后出现 200 → Manager 密码被暴力破解

PUT /manager/text/deploy → WAR 包部署操作(高度可疑

非管理 IP 访问 Manager → 未授权访问

1.5 日志配置文件位置

配置项 配置文件
访问日志格式和开关 $CATALINA_HOME/conf/server.xml (AccessLogValve)
日志级别和 Handler $CATALINA_HOME/conf/logging.properties
Manager 应用配置 $CATALINA_HOME/conf/tomcat-users.xml
应用级日志(Log4j/Logback) 各应用 WEB-INF 下的日志配置文件

应急时的检查命令:

1
2
3
4
5
6
7
8
9
10
11
12
# 定位 Tomcat 根目录
CATALINA_HOME=$(ps aux | grep tomcat | grep -v grep | grep -oP 'catalina\.home=\K\S+' | head -1)
echo "Tomcat Home: $CATALINA_HOME"

# 检查日志配置
cat "$CATALINA_HOME/conf/logging.properties"

# 检查访问日志是否开启
grep -A5 "AccessLogValve" "$CATALINA_HOME/conf/server.xml"

# 检查 Manager 用户配置(可能包含弱密码)
cat "$CATALINA_HOME/conf/tomcat-users.xml"

二、常见 Tomcat 入侵方式

2.1 WAR 文件部署攻击

攻击原理

Tomcat Manager 提供了通过 Web 界面或 API 部署 WAR 包的功能

攻击者获取 Manager 凭据后,可以部署包含 Webshell 的 WAR 包

Manager 默认凭据:tomcat/tomcat, admin/admin, manager/manager

检测方法一:日志分析

1
2
3
4
5
6
7
8
9
10
11
# 搜索 Manager 接口的访问记录
grep "/manager/" /opt/tomcat/logs/localhost_access_log.*.txt

# 筛选部署操作
grep -E "deploy|undeploy|PUT.*\.war" /opt/tomcat/logs/localhost_access_log.*.txt

# 筛选 Manager 暴力破解(大量 401 响应)
grep "/manager/" /opt/tomcat/logs/localhost_access_log.*.txt | awk '{print $1, $NF}' | grep " 401" | awk '{print $1}' | sort | uniq -c | sort -rn

# 搜索 catalina.out 中的部署记录
grep -i "Deploying web application" /opt/tomcat/logs/catalina.out

检测方法二:文件系统检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 检查 webapps 目录下的所有应用
ls -la /opt/tomcat/webapps/

# 查找可疑的 WAR 文件(与已知应用对比)
find /opt/tomcat/webapps/ -name "*.war" -exec ls -la {} \;

# 查找最近部署的应用(按修改时间排序)
ls -lt /opt/tomcat/webapps/

# 检查 WAR 文件的部署时间
stat /opt/tomcat/webapps/*.war

# 解压可疑 WAR 并检查内容
mkdir /tmp/war_analysis
cp /opt/tomcat/webapps/suspicious.war /tmp/war_analysis/
cd /tmp/war_analysis && jar -xf suspicious.war
find . -name "*.jsp" -o -name "*.class" | head -20

Manager 弱密码检查

1
2
3
4
5
6
7
8
9
# 检查 tomcat-users.xml 中的用户配置
cat /opt/tomcat/conf/tomcat-users.xml | grep -v "^<!--" | grep -v "^$"

# 常见弱密码列表
# tomcat / tomcat
# admin / admin
# manager / manager
# tomcat / s3cret
# admin / (空密码)

2.2 JSP Webshell

文件系统检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查找所有 JSP 文件,按修改时间排序
find /opt/tomcat/webapps/ -name "*.jsp" -exec ls -la {} \; | sort -k6,7

# 查找比 web.xml 更新的 JSP(部署后新增的文件大概率可疑)
find /opt/tomcat/webapps/ -name "*.jsp" -newer /opt/tomcat/webapps/ROOT/WEB-INF/web.xml

# 查找具有可疑文件名的 JSP
find /opt/tomcat/webapps/ -name "*.jsp" | grep -iE "shell|cmd|exec|backdoor|hack|test|upload|eval|run|spy|tunnel"

# 查找隐藏目录中的 JSP
find /opt/tomcat/webapps/ -path "*/.*/*.jsp"

# 查找异常位置的 JSP(如 META-INF、WEB-INF 外的非标准位置)
find /opt/tomcat/webapps/ -name "*.jsp" -not -path "*/WEB-INF/*"

内容特征检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 搜索 JSP 文件中的命令执行代码
grep -rl "Runtime.getRuntime().exec" /opt/tomcat/webapps/ --include="*.jsp"
grep -rl "ProcessBuilder" /opt/tomcat/webapps/ --include="*.jsp"

# 搜索反射调用(高级 Webshell 常用)
grep -rl "Class.forName\|getMethod\|invoke(" /opt/tomcat/webapps/ --include="*.jsp"

# 搜索文件操作(上传/下载功能)
grep -rl "FileOutputStream\|FileInputStream\|MultipartFile" /opt/tomcat/webapps/ --include="*.jsp"

# 搜索编码/解码(混淆 Webshell)
grep -rl "Base64.decode\|base64Decode\|URLDecoder" /opt/tomcat/webapps/ --include="*.jsp"

# 搜索网络连接(反弹 Shell)
grep -rl "Socket\|ServerSocket\|URLConnection" /opt/tomcat/webapps/ --include="*.jsp"

# 搜索 ClassLoader(动态加载类,可能是高级 Webshell)
grep -rl "ClassLoader\|defineClass\|loadClass" /opt/tomcat/webapps/ --include="*.jsp"

# 综合检测:一行命令检测多种特征
find /opt/tomcat/webapps/ -name "*.jsp" -exec grep -lE \
"Runtime\.getRuntime|ProcessBuilder|Class\.forName|Base64\.decode|FileOutputStream|Socket|defineClass|invoke\(" {} \;

常见 JSP Webshell 代码特征

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<%-- 最简单的命令执行 Webshell --%>
<%
String cmd = request.getParameter("cmd");
Runtime.getRuntime().exec(cmd);
%>

<%-- 带回显的 Webshell --%>
<%
Process p = Runtime.getRuntime().exec(request.getParameter("cmd"));
java.io.InputStream is = p.getInputStream();
// ... 读取输出并返回
%>

<%-- 冰蝎/哥斯拉等工具的 Webshell 通常更复杂 --%>
<%-- 特征:Base64 解码 + ClassLoader 动态加载 + AES 加密通信 --%>

2.3 AJP Ghostcat (CVE-2020-1938)

漏洞概述

影响 Tomcat 版本:< 9.0.31, < 8.5.51, < 7.0.100

AJP 协议(Apache JServ Protocol)的设计缺陷

攻击者可以通过 AJP 端口(默认 8009)读取 Tomcat webapp 目录下的任意文件

配合文件包含可以实现远程代码执行

检测方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 检查 AJP 端口是否开放
ss -tlnp | grep 8009
netstat -tlnp | grep 8009

# 检查 server.xml 中的 AJP 连接器配置
grep -A3 "AJP" /opt/tomcat/conf/server.xml

# 检查 Tomcat 版本
cat /opt/tomcat/RELEASE-NOTES | head -5
# 或
java -cp /opt/tomcat/lib/catalina.jar org.apache.catalina.util.ServerInfo

# 检查是否有来自外部的 AJP 连接
ss -tnp | grep 8009

修复方法

1
2
3
4
5
6
7
8
9
10
11
# 方法1:禁用 AJP(如果不需要)
# 在 server.xml 中注释掉 AJP Connector
# <Connector port="8009" protocol="AJP/1.3" ... />

# 方法2:设置 AJP Secret(Tomcat 9.0.31+)
# <Connector port="8009" protocol="AJP/1.3" secret="your_secret_key" />

# 方法3:限制 AJP 监听地址
# <Connector port="8009" protocol="AJP/1.3" address="127.0.0.1" />

# 方法4:升级 Tomcat 到安全版本

2.4 反序列化攻击

背景

Java 反序列化漏洞是 Java 生态中影响最广泛的漏洞类型之一

当应用对不受信任的数据进行反序列化时,攻击者可以构造恶意序列化对象实现 RCE

常见受影响组件:Commons Collections, Commons BeanUtils, Spring Framework 等

检测 classpath 中的危险库

1
2
3
4
5
6
7
8
9
10
11
# 查找 commons-collections(最常被利用的库)
find /opt/tomcat/ -name "commons-collections*.jar" 2>/dev/null

# 查找其他常见危险库
find /opt/tomcat/ -name "*.jar" | xargs -I {} basename {} | sort -u | grep -iE "commons-collections|commons-beanutils|spring-core|fastjson|jackson-databind|xstream|c3p0|rome|jndi"

# 检查应用 WEB-INF/lib 下的所有依赖
for app_dir in /opt/tomcat/webapps/*/WEB-INF/lib; do
echo "=== $app_dir ==="
ls "$app_dir" | grep -iE "commons-collections|beanutils|fastjson"
done

日志中的反序列化攻击痕迹

1
2
3
4
5
6
7
8
# 搜索反序列化异常
grep -i "InvalidClassException\|ClassNotFoundException\|deserialize\|readObject\|REJECTED" /opt/tomcat/logs/catalina.out

# 如果配置了 JEP 290 序列化过滤器,搜索过滤日志
grep -i "ObjectInputFilter\|REJECTED\|serialFilter" /opt/tomcat/logs/catalina.out

# 搜索常见攻击链中的类名
grep -i "InvokerTransformer\|ChainedTransformer\|ConstantTransformer\|LazyMap\|TiedMapEntry\|TemplatesImpl" /opt/tomcat/logs/catalina.out

三、内存马检测(重点)

关联已有笔记:本节内容与你的内存马系列笔记形成”攻防对照”。攻击原理详见 01-内存马概述02-Servlet型内存马03-Spring型内存马;检测与防御方法论见 06-检测与防御。此处侧重应急响应场景下的实战检测操作

3.1 内存马与传统 Webshell 的区别

对比维度 传统 Webshell (JSP) 内存马
存在形式 磁盘上的文件 (.jsp/.jspx) 仅在 JVM 内存中
文件扫描 可被 find/grep 发现 磁盘上无文件
杀软检测 文件查杀可发现 传统杀软无法检测
重启后存活 文件仍在,重启后仍可访问 重启后消失(除非有持久化机制)
流量特征 访问特定 JSP 路径 可能劫持正常 URL 路径
检测难度

关键线索 — 如果你发现以下情况,需要怀疑内存马:

访问日志中有对可疑 URL 的请求,但磁盘上找不到对应文件

应用中出现了未在 web.xml 中注册的 Servlet/Filter

Spring 应用中出现了未在源码中定义的 Controller/Interceptor

jstack 输出中出现异常的线程名或异常类名

3.2 基础检测:Java 进程分析

定位 Java/Tomcat 进程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 列出所有 Java 进程
jps -lv

# 输出示例:
# 12345 org.apache.catalina.startup.Bootstrap -Dcatalina.home=/opt/tomcat ...
# 12678 com.example.springboot.Application --server.port=8080
# 12900 sun.tools.jps.Jps -lv

# 获取 Tomcat 进程的详细信息
ps aux | grep "[t]omcat"

# 查看 Tomcat 进程的启动命令和参数
cat /proc/<PID>/cmdline | tr '\0' ' '

# 查看进程打开的文件
lsof -p <PID> | head -50

# 查看进程的网络连接
lsof -p <PID> -i

线程 Dump 分析

1
2
3
4
5
6
7
8
9
10
11
12
# 生成线程 dump
jstack <PID> > /tmp/thread_dump.txt

# 搜索可疑线程名
grep -i "shell\|cmd\|exec\|eval\|backdoor\|hack" /tmp/thread_dump.txt

# 搜索可疑的类名(非正常应用包名)
grep -E "at [a-z]{1,3}\." /tmp/thread_dump.txt # 短包名通常是恶意类
grep -vE "at (java|javax|org\.apache|com\.sun|sun\.)" /tmp/thread_dump.txt | grep "at "

# 查看线程状态统计
grep "java.lang.Thread.State" /tmp/thread_dump.txt | sort | uniq -c

类加载信息分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看 JVM 加载的类统计(按实例数量排序)
jmap -histo <PID> | head -50

# 搜索可疑类名
jmap -histo <PID> | grep -iE "shell|cmd|exec|hack|backdoor|memshell|inject|agent"

# 使用 jcmd 查看类加载信息
jcmd <PID> GC.class_histogram | head -50

# 查看 JVM 系统属性(可能显示 Agent 注入痕迹)
jcmd <PID> VM.system_properties | grep -iE "agent|attach|instrument"

# 查看 JVM flags
jcmd <PID> VM.flags

3.3 内存马类型与对应检测方法

Servlet/Filter/Listener 型内存马检测

原理回顾(详见 02-Servlet型内存马):

攻击者通过反序列化、JNDI 注入等方式获得代码执行能力

动态注册一个恶意的 Servlet、Filter 或 Listener 到 Tomcat 的 Context 中

后续通过正常 HTTP 请求触发恶意代码

检测思路:

对比 web.xml 中声明的组件与运行时实际注册的组件

动态注册的组件不会出现在 web.xml 中 → 差异即可疑

实战检测方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 方法1:使用 Arthas 检测动态注册的 Servlet/Filter
# 安装 Arthas
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar <PID>

# 在 Arthas 交互界面中:
# 查看所有 Filter
# mbean org.apache.catalina:type=Filter,*

# 查看所有 Servlet
# mbean org.apache.catalina:type=Servlet,*

# 方法2:通过 JMX 检查
# 使用 jconsole 或 VisualVM 连接到 Tomcat 进程
# 检查 Catalina -> Context -> Servlet/Filter Mappings

# 方法3:写一个检测 JSP 部署到应用中
# 该 JSP 遍历 ServletContext 中注册的所有 Servlet/Filter/Listener
# 并与 web.xml 声明进行对比

Spring Controller/Interceptor 型内存马检测

原理回顾(详见 03-Spring型内存马):

攻击者将恶意 Controller 或 HandlerInterceptor 注册到 Spring MVC 的 RequestMappingHandlerMapping 中

或注册恶意的 WebFlux HandlerFunction(Reactive 场景)

检测思路:

列出所有注册的 RequestMapping,与源码对比

列出所有 Interceptor,查找未在配置中声明的

实战检测:

1
2
3
4
5
6
7
8
9
10
# 如果应用开启了 Spring Actuator
# 检查所有注册的 URL 映射
curl http://localhost:8080/actuator/mappings 2>/dev/null | python3 -m json.tool | head -100

# 检查 Bean 列表(可能发现异常的 Bean)
curl http://localhost:8080/actuator/beans 2>/dev/null | python3 -m json.tool | head -100

# 如果 Actuator 未开启,使用 Arthas
# 在 Arthas 中查看 RequestMappingHandlerMapping 中的所有映射
# ognl '@org.springframework.web.context.support.WebApplicationContextUtils@getWebApplicationContext(#request.getServletContext()).getBean("requestMappingHandlerMapping").getHandlerMethods()'

Agent 型内存马检测

原理:通过 Java Agent 的 Instrumentation API 修改已加载类的字节码

这是最隐蔽的内存马类型,因为它不新增组件,而是修改已有组件的行为

检测方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 检查是否有 Agent 被附加
jcmd <PID> VM.system_properties | grep -i "agent"

# 检查 /tmp 目录下的 .attach_pid 文件(Agent Attach 痕迹)
ls -la /tmp/.attach_pid*

# 检查进程的 java.io.tmpdir 下是否有可疑的 jar 文件
TMPDIR=$(jcmd <PID> VM.system_properties | grep java.io.tmpdir | awk -F= '{print $2}')
ls -la "$TMPDIR"/*.jar 2>/dev/null

# 使用 sa-jdi.jar (Serviceability Agent) dump 类字节码进行对比
# 将运行时的 class 与原始 jar 中的 class 进行对比
# 如果字节码不一致,说明类被修改过(可能是 Agent 型内存马)

3.4 Arthas 实战检测

Arthas 是阿里开源的 Java 诊断工具,在内存马检测中非常有用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 下载并启动 Arthas
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
# 选择要附加的 Java 进程

# === 核心检测命令 ===

# 1. 搜索可疑类
sc *Shell*
sc *Cmd*
sc *Exec*
sc *Backdoor*
sc *Memshell*
sc *Inject*

# 2. 查看类的详细信息(包括类加载器、来源)
sc -d com.example.SuspiciousClass

# 3. 反编译可疑类查看源码
jad com.example.SuspiciousClass

# 4. 查看某个类的所有方法
sm com.example.SuspiciousClass

# 5. 监控某个方法的调用
watch com.example.SuspiciousClass * '{params, returnObj, throwExp}' -x 3

# 6. 查看类加载器树
classloader -t

# 7. 搜索所有 Filter 类
sc javax.servlet.Filter -d | grep -E "class-info|classLoaderHash|code-source"

# 8. 搜索所有 Servlet 类
sc javax.servlet.http.HttpServlet -d | grep -E "class-info|classLoaderHash|code-source"

关键判断依据:

如果某个 Filter/Servlet 的 code-source 为 null → 高度可疑,可能是内存马

如果某个类的 ClassLoader 异常 → 可能是动态加载的恶意类

如果反编译后发现命令执行、文件操作等代码 → 确认为内存马

3.5 内存 Dump 分析

当在线分析困难时,可以 dump 整个 JVM 堆内存进行离线分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 生成堆 dump 文件
jmap -dump:format=b,file=/tmp/heap.bin <PID>

# 注意:堆 dump 可能很大(GB 级别),确保磁盘空间充足
# 生成过程会导致 JVM 短暂停顿(Stop-The-World),生产环境慎用

# dump 文件可以使用以下工具分析:
# - Eclipse MAT (Memory Analyzer Tool)
# - VisualVM
# - jhat(JDK 自带,适合命令行)

# 使用 jhat 快速分析(启动一个 Web 界面)
jhat -port 7401 /tmp/heap.bin
# 访问 http://localhost:7401 查看分析结果

# 在 dump 文件中搜索字符串
strings /tmp/heap.bin | grep -iE "shell|cmd|exec|eval|backdoor" | sort -u | head -50

# 搜索常见内存马的类名特征
strings /tmp/heap.bin | grep -iE "memshell|godzilla|behinder|antSword|ice_scorpion" | sort -u

四、Tomcat 进程深度分析

4.1 进程基础信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 列出所有 Java 进程及其启动参数
jps -lv

# 查看 Tomcat 进程的完整命令行
ps -ef | grep "[t]omcat"

# 查看进程的环境变量
cat /proc/<PID>/environ | tr '\0' '\n'

# 查看进程的工作目录
ls -la /proc/<PID>/cwd

# 查看进程打开的文件描述符
ls -la /proc/<PID>/fd | wc -l # 总数
ls -la /proc/<PID>/fd | head -50 # 前 50 个

4.2 jstack 线程分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 完整线程 dump
jstack <PID> > /tmp/thread_dump_$(date +%Y%m%d_%H%M%S).txt

# 多次 dump 对比(间隔 5 秒,用于发现活跃的恶意线程)
for i in 1 2 3; do
jstack <PID> > /tmp/thread_dump_${i}.txt
sleep 5
done

# 分析高 CPU 线程
# 首先找到高 CPU 的线程 ID(十进制)
top -H -p <PID> -bn 1 | head -20

# 将线程 ID 转为十六进制,然后在 jstack 输出中搜索
printf "%x\n" <THREAD_ID>
# 在 thread dump 中搜索 nid=0x<十六进制>

可疑线程特征:

线程名包含 shell、cmd、exec 等关键字

线程栈中出现 Runtime.exec, ProcessBuilder.start

线程栈中出现非应用包名的异常类

异常的守护线程(Daemon Thread),尤其是在 WAITINGTIMED_WAITING 状态

4.3 jcmd 综合诊断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 查看可用的诊断命令
jcmd <PID> help

# 查看 JVM 系统属性
jcmd <PID> VM.system_properties

# 查看 JVM 启动参数
jcmd <PID> VM.command_line
jcmd <PID> VM.flags

# 查看加载的类直方图(按实例数量)
jcmd <PID> GC.class_histogram | head -50

# 搜索可疑类
jcmd <PID> GC.class_histogram | grep -iE "shell|cmd|exec|backdoor|inject|memshell"

# 查看类加载器统计
jcmd <PID> VM.classloader_stats

# 触发 GC(有时可以清除一些弱引用的恶意对象)
jcmd <PID> GC.run

# 查看编译器信息
jcmd <PID> Compiler.directives_print

4.4 jmap 内存分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看堆内存使用概况
jmap -heap <PID>

# 查看对象实例统计(不触发 Full GC)
jmap -histo <PID> | head -30

# 查看对象实例统计(触发 Full GC,更准确)
jmap -histo:live <PID> | head -30

# 生成完整堆 dump
jmap -dump:format=b,file=/tmp/heap_$(date +%Y%m%d_%H%M%S).bin <PID>

# 仅 dump 存活对象(触发 Full GC)
jmap -dump:live,format=b,file=/tmp/heap_live.bin <PID>

分析要点:

大量的 byte[] 对象 → 可能在处理恶意 payload

异常的 Class 对象数量 → 可能在动态生成恶意类

非应用包名的对象出现在 Top 列表中 → 需要排查

五、应急处置

5.1 WAR Webshell 清理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1. 识别恶意 WAR 包和解压目录
ls -lt /opt/tomcat/webapps/

# 2. 停止 Tomcat(如果可以接受停机)
systemctl stop tomcat
# 或
/opt/tomcat/bin/shutdown.sh

# 3. 删除恶意 WAR 和解压目录
rm -rf /opt/tomcat/webapps/suspicious.war
rm -rf /opt/tomcat/webapps/suspicious/

# 4. 清理 Tomcat 临时文件
rm -rf /opt/tomcat/work/Catalina/localhost/suspicious/

# 5. 检查其他 webapps 目录是否也有后门
find /opt/tomcat/webapps/ -name "*.jsp" -newer /opt/tomcat/webapps/ROOT/WEB-INF/web.xml -exec ls -la {} \;

# 6. 重启 Tomcat
systemctl start tomcat

5.2 JSP Webshell 清理

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. 备份证据
mkdir -p /tmp/evidence/webshell
cp /opt/tomcat/webapps/app/shell.jsp /tmp/evidence/webshell/
md5sum /opt/tomcat/webapps/app/shell.jsp > /tmp/evidence/webshell/hash.txt

# 2. 删除 Webshell 文件
rm /opt/tomcat/webapps/app/shell.jsp

# 3. 清理编译缓存(JSP 会被编译为 .class)
find /opt/tomcat/work/ -name "*.class" -newer /opt/tomcat/webapps/ROOT/WEB-INF/web.xml -delete

# 4. 检查是否还有其他 Webshell
find /opt/tomcat/webapps/ -name "*.jsp" -exec grep -lE "Runtime\.getRuntime|ProcessBuilder|defineClass|ClassLoader" {} \;

5.3 内存马清理

内存马清理比文件 Webshell 复杂得多:

方法一:重启 Tomcat(最简单但影响业务)

1
2
3
4
5
6
7
8
9
# 重启后内存马消失(除非有持久化机制重新注入)
systemctl restart tomcat

# 重启后立即检查是否重新出现
# 如果重启后内存马又出现了,说明存在持久化注入点
# 需要排查:
# - 应用代码中是否被植入了注入逻辑
# - 是否有恶意 jar 包在 classpath 中
# - 是否修改了 Tomcat 本身的 jar(如 catalina.jar)

方法二:使用 Agent 动态卸载(不停机)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 使用 Arthas 或自定义 Agent 卸载恶意组件
# 以 Arthas 为例:

# 1. 连接到目标进程
java -jar arthas-boot.jar <PID>

# 2. 确认恶意组件
# sc -d <恶意类名>

# 3. 使用 ognl 动态移除 Filter(示例)
# ognl '#context=@org.apache.catalina.core.ApplicationFilterChain@lastServicedRequest.get().getServletContext(),
# #context.removeFilterMapping("恶意FilterName")'

# 注意:具体的卸载命令取决于内存马的注入方式
# 详细方法参考 [06-检测与防御](/2026/04/04/内存马-06-检测与防御/)

方法三:排查并清理持久化注入点

1
2
3
4
5
6
7
8
9
10
11
12
# 检查是否有恶意 jar 被添加到 classpath
find /opt/tomcat/lib/ -name "*.jar" -mtime -30 -exec ls -la {} \;

# 对比 Tomcat 原始 lib 目录(使用干净的同版本 Tomcat 作为基准)
diff <(ls /opt/tomcat/lib/) <(ls /opt/tomcat-clean/lib/)

# 检查应用的 WEB-INF/lib 是否有新增的 jar
find /opt/tomcat/webapps/*/WEB-INF/lib/ -name "*.jar" -mtime -30 -exec ls -la {} \;

# 校验 Tomcat 核心 jar 文件的完整性
md5sum /opt/tomcat/lib/catalina.jar
# 与官方发布的同版本 jar 的 hash 对比

5.4 Tomcat 安全加固

Manager 安全配置

1
2
3
4
5
6
7
8
9
10
11
<!-- tomcat-users.xml: 使用强密码 -->
<tomcat-users>
<role rolename="manager-gui"/>
<user username="admin" password="C0mpl3x!P@ssw0rd#2026" roles="manager-gui"/>
</tomcat-users>

<!-- manager/META-INF/context.xml: 限制访问 IP -->
<Context antiResourceLocking="false" privileged="true">
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="10\.0\.0\.\d+|192\.168\.1\.\d+" />
</Context>

AJP 加固

1
2
3
4
5
6
7
8
<!-- server.xml: 禁用 AJP 或绑定本地 + 设置 Secret -->
<!-- 禁用(注释掉) -->
<!-- <Connector port="8009" protocol="AJP/1.3" /> -->

<!-- 或限制监听 + Secret -->
<Connector port="8009" protocol="AJP/1.3"
address="127.0.0.1"
secret="your_strong_secret_key" />

运行权限

1
2
3
4
5
6
7
8
# Tomcat 不应以 root 用户运行
# 创建专用用户
useradd -r -s /sbin/nologin tomcat
chown -R tomcat:tomcat /opt/tomcat

# 限制目录权限
chmod -R 750 /opt/tomcat/
chmod -R 700 /opt/tomcat/conf/

移除不必要的应用

1
2
3
4
5
6
# 删除默认的示例和文档应用
rm -rf /opt/tomcat/webapps/docs
rm -rf /opt/tomcat/webapps/examples
rm -rf /opt/tomcat/webapps/host-manager
# Manager 如果不需要也建议删除
# rm -rf /opt/tomcat/webapps/manager

隐藏版本信息

1
2
3
<!-- server.xml: 修改 Server header -->
<Connector port="8080" protocol="HTTP/1.1"
server="WebServer" />

配置安全头部

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- web.xml: 添加安全响应头 -->
<filter>
<filter-name>httpHeaderSecurity</filter-name>
<filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>
<init-param>
<param-name>antiClickJackingEnabled</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>httpHeaderSecurity</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

六、实战练习

6.1 实验环境

实验目录:labs/02-tomcat-intrusion/

环境要求:

Tomcat 8.5/9.0 环境

JDK 8/11

一个简单的 Java Web 应用

6.2 练习一:WAR 部署攻击检测

场景:某 Tomcat 服务器被发现对外提供了一个未知的 Web 应用

任务:

分析 Manager 访问日志,确定攻击来源

定位并分析恶意 WAR 包

清理恶意应用并加固 Manager

6.3 练习二:内存马检测

场景:安全设备告警某 Tomcat 服务器向外部 IP 发起异常连接,但文件扫描未发现 Webshell

任务:

使用 jps/jstack/jmap 初步分析

安装并使用 Arthas 进行深入检测

确认内存马类型(Servlet/Filter/Spring)

生成堆 dump 并提取恶意类的字节码

清理内存马

6.4 练习三:综合应急

场景:一台运行 Spring Boot 应用的服务器被入侵,攻击路径为 Fastjson 反序列化 → JNDI 注入 → 内存马植入

任务:

从网络告警出发,定位被入侵的服务

分析应用日志确定漏洞利用方式

检测并清理内存马

修复 Fastjson 漏洞

编写完整的应急响应报告

6.5 思考题

如果攻击者同时植入了文件 Webshell 和内存马作为双重后门,你的排查流程是什么?

Agent 型内存马通过修改已有类的字节码实现,如何确认某个类的字节码是否被篡改?

Spring Boot Fat JAR 部署模式下,Webshell 排查有什么不同?

如果生产环境不允许安装 Arthas(安全合规要求),还有哪些检测内存马的替代方案?


上一章 目录 下一章
10-SSH暴力破解与未授权访问 Linux应急响应 12-Nginx与Apache应急