Linux 基础体系 · 第 85/85 篇。示例面向现代主流 Linux 发行版;发行版差异、权限和生产风险会明确说明。

Linux 主机事件响应:隔离、取证、时间线、证据保全和恢复

Linux 主机事件响应,是在怀疑主机遭到入侵、恶意程序执行、凭据泄露、越权操作或异常配置变更后,对主机进行控制影响、保存证据、重建事实、修复根因并安全恢复服务的过程。

它不是“登录服务器后执行几条检查命令”,也不是简单地删除恶意文件。响应人员必须同时处理两个目标:

  1. 降低继续危害的概率:阻断横向移动、数据外传和持久化。
  2. 尽量保留能够证明事实的证据:包括内存、进程、网络连接、日志、文件元数据和磁盘内容。

这两个目标经常冲突。例如,立即关机会阻止攻击者继续操作,却会丢失内存中的进程、密钥和网络状态;直接删除恶意程序可能暂时止血,却会破坏分析所需的样本和文件时间信息。因此,事件响应本质上是在不确定信息下进行的有证据约束的状态转换


一、先建立响应模型:你要回答哪些问题

一次完整的主机事件响应,至少要回答以下问题:

  • 发生了什么:是误报、配置错误、凭据滥用,还是主机已经被执行了未授权代码?
  • 何时发生:攻击者首次进入、获得权限、建立持久化、访问数据和离开的时间分别是什么?
  • 从哪里进入:SSH 密钥、密码、暴露服务、漏洞、供应链软件,还是已有主机上的凭据?
  • 攻击者做了什么:执行过哪些程序,读取或修改过哪些文件,访问过哪些网络目标?
  • 影响边界在哪里:只有一台主机,还是同一凭据、镜像、密钥或软件版本导致多台主机受影响?
  • 现在是否仍在继续:是否有活动进程、反连、定时任务、systemd 服务、内核模块或其他持久化机制?
  • 恢复后如何证明风险下降:根因是否修复,凭据是否轮换,服务是否经过验证,监控和审计是否恢复?

可以把主机状态抽象为:

S=(P,N,F,L,M,C)S = (P, N, F, L, M, C)

其中:

  • PP:进程和内核对象状态;
  • NN:网络连接、监听端口和路由状态;
  • FF:文件系统及其元数据;
  • LL:日志、审计和命令记录;
  • MM:内存中的凭据、进程映像和临时数据;
  • CC:配置、凭据、信任关系和外部依赖。

隔离、取证、恢复不是对某一个文件操作,而是改变这个状态向量。比如:

  • 断开网络主要改变 NN,但可能触发服务退出并改变 PP
  • 关机会清除 MM,并使部分 PPNN 不可再观察;
  • 删除恶意文件会改变 FF,同时破坏原始证据;
  • 轮换密钥改变 CC,但不能证明过去没有被使用。

因此,所有操作都应记录“操作前状态、操作动作、操作后状态和执行人”。


二、证据、线索和结论不是同一个概念

1. 证据的三个层次

响应过程中常见的材料可以分为三个层次:

  • 原始数据:例如磁盘镜像、内存采集结果、原始日志文件。
  • 派生数据:例如从镜像中导出的文件、从日志生成的时间线、从审计日志筛选出的事件。
  • 分析结论:例如“攻击者通过某个 SSH 密钥登录后执行了下载命令”。

派生数据和结论都必须能够追溯到原始数据。否则,后续复核时无法判断筛选是否遗漏、时区是否转换错误、工具是否修改了文件。

2. 证据不等于“看起来可疑”

以下现象只能作为线索,不能单独证明入侵:

  • /tmp 中出现二进制文件;
  • 进程名与常见系统进程相似;
  • SSH 日志中出现海外 IP;
  • 某个文件的修改时间很新;
  • ps 看到一个未知进程;
  • auditd 记录了某次执行。

例如,/tmp 中的文件可能是编译器、安装程序或应用临时文件;海外 IP 可能是公司出口、VPN 或云厂商;文件修改时间可能由解包、恢复备份或时间戳伪造造成。

更可靠的判断通常需要多个独立来源相互印证:

结论可信度ESSHEauditEnetworkEfile\text{结论可信度} \uparrow \quad \text{当} \quad E_{\text{SSH}} \cap E_{\text{audit}} \cap E_{\text{network}} \cap E_{\text{file}}

这里的交集不是数学上必须完全相同,而是指不同证据源对同一事件在时间、主体和动作上相互支持。


三、响应前的决策:先隔离还是先取证

1. 影响优先级

可用以下因素决定动作顺序:

情况 首要动作
正在进行数据外传、勒索、破坏或横向移动 立即隔离网络,必要时停止服务
仅发现可疑文件,未发现活动连接 先进行有限的易失数据采集,再隔离
内存中可能存在攻击者控制、密钥或反连 优先可信环境采集内存或网络隔离后采集
业务为高可用集群,存在健康副本 先从流量层摘除受影响节点,再保留节点取证
机器是唯一生产实例,停止会造成重大损失 先执行最小破坏性的隔离和采集,并同步升级决策

这里的“先取证”不是无限期观察。攻击者继续活动会改变现场、删除日志、加密数据,延迟本身也是证据损失。

2. 隔离不等于关机

隔离是阻止主机继续与不可信系统通信,常见层次包括:

  1. 流量层隔离:从负载均衡器、服务发现或路由中摘除主机。
  2. 网络层隔离:安全组、交换机端口、VLAN、ACL 或防火墙限制出入站。
  3. 主机层隔离:在主机上设置防火墙规则或停止特定服务。
  4. 电源层隔离:关机、断电或通过带外管理停止实例。

优先使用主机外部的隔离手段。被攻陷的主机上的防火墙命令可能被拦截、替换或触发异常;同时,修改规则本身也会改变现场。

一个常见状态流如下:

stateDiagram-v2
    [*] --> Normal: 正常运行
    Normal --> Suspected: 告警或异常线索
    Suspected --> Contained: 网络/服务隔离
    Suspected --> VolatileCapture: 需要保留易失数据
    VolatileCapture --> Contained: 采集完成
    Contained --> DiskAcquisition: 磁盘或文件级取证
    DiskAcquisition --> Analysis: 时间线与根因分析
    Analysis --> Rebuild: 无法可信清理或高权限失陷
    Analysis --> Remediate: 根因和持久化已明确
    Remediate --> Validate: 修复、轮换、验证
    Rebuild --> Validate: 重装并恢复
    Validate --> Monitor: 灰度上线与加强监控
    Monitor --> Closed: 复盘与留存

关键点是:ContainedVolatileCapture 可以根据风险先后调整,但不能把“已隔离”误认为“已清除”。

3. 示例:主机级隔离的风险

以下命令在某些 Linux 系统上可阻止所有新建连接:

sudo nft list ruleset
sudo nft add table inet ir
sudo nft 'add chain inet ir input { type filter hook input priority -100; policy drop; }'
sudo nft 'add chain inet ir output { type filter hook output priority -100; policy drop; }'

它们的前提和风险是:

  • 系统使用 nftables,并且当前用户有 CAP_NET_ADMIN 或 root 权限;
  • 可能中断 SSH、监控、存储和取证传输;
  • 规则写入内核后会改变网络状态;
  • 如果没有带外管理,可能把响应人员锁在主机外;
  • 某些发行版通过 firewalld、ufw 或云代理管理规则,直接修改 nftables 可能被覆盖。

因此,生产环境通常应先使用云安全组、交换机 ACL 或负载均衡器隔离。若必须本机操作,应先记录当前规则,并准备带外恢复路径:

sudo nft list ruleset > /safe/ir/nft-before.txt
date -u --iso-8601=ns | tee -a /safe/ir/actions.log

“安全目录”应位于可信的外部存储或只写采集介质;如果 /safe/ir 仍在被调查的本机上,它不能自动成为可信保存位置。


四、易失数据取证:先保存会消失的事实

1. 什么是易失数据

易失数据是关机、进程退出、网络变化或内核状态更新后可能丢失或改变的数据,典型包括:

  • 当前时间和时区;
  • 进程树及命令行;
  • 加载的内核模块;
  • 网络接口、路由、监听端口和连接;
  • 登录会话;
  • /proc 中的进程环境和打开文件;
  • 内存中的凭据、临时脚本和进程映像;
  • 临时目录中的未落盘内容。

采集顺序通常是从变化最快、最容易消失的数据开始,再采集稳定数据:

  1. 记录采集人员、主机标识、UTC 时间;
  2. 采集网络连接和进程;
  3. 采集登录会话、挂载点、内核模块;
  4. 采集关键进程的 /proc 信息;
  5. 视风险和工具能力采集内存;
  6. 再进行文件和日志采集。

2. 使用可信工具和绝对路径

如果攻击者修改了 PATH、替换了 psssls,直接执行命令的结果可能不可信。可以先记录命令路径和校验值:

command -v ps ss ip ls date sha256sum
type -a ps ss ip
sha256sum /usr/bin/ps /usr/bin/ss /usr/sbin/ip /usr/bin/ls

路径因发行版而异,不能假设所有程序都位于相同目录。更高可信度的做法是:

  • 从可信救援介质启动;
  • 通过带外管理或虚拟机快照获取数据;
  • 在隔离环境中挂载磁盘只读分析;
  • 将采集结果直接写入外部介质或通过受控链路传出。

3. 一个最小的现场采集脚本

下面脚本用于快速记录状态,不是完整内存取证,也不能替代磁盘镜像。它应从可信路径执行,并把输出写到外部挂载点。

#!/usr/bin/env bash
set -u

OUT=${1:?usage: $0 /external/ir-dir}
mkdir -p -- "$OUT"
exec > >(tee -a "$OUT/collection.log") 2>&1

echo "=== collection ==="
date -u --iso-8601=ns
hostnamectl 2>/dev/null || hostname
id
cat /etc/os-release 2>/dev/null || true
cat /proc/sys/kernel/random/boot_id 2>/dev/null || true

echo "=== processes ==="
/usr/bin/ps -e -o pid,ppid,user,lstart,etimes,stat,cmd --forest

echo "=== network ==="
/usr/sbin/ss -lntup
/usr/sbin/ss -antup
/usr/sbin/ip addr
/usr/sbin/ip route

echo "=== sessions ==="
/usr/bin/w
/usr/bin/who
/usr/bin/last -Fai | head -100

echo "=== mounts and kernel ==="
/usr/bin/findmnt -R
/usr/bin/lsmod 2>/dev/null || true

echo "=== important persistence ==="
systemctl list-unit-files --state=enabled --no-pager 2>/dev/null || true
systemctl list-timers --all --no-pager 2>/dev/null || true

逐步说明:

  • date -u --iso-8601=ns 记录 UTC 纳秒时间,避免后续混淆本地时区;
  • boot_id 用于区分本次启动与上次启动;
  • pslstart 是进程启动时间,etimes 是已运行秒数,两者可相互校验;
  • ss -lntup 展示监听 TCP 端口及关联进程,但显示进程信息通常需要 root;
  • ss -antup 展示已建立和其他 TCP 状态,连接可能在采集期间变化;
  • systemctl 只反映 systemd 管理范围,不能覆盖所有持久化方式;
  • findmnt 比仅查看 /etc/fstab 更接近当前实际挂载状态。

pssssystemctl 的结果都是实时快照,不具有天然不可篡改性。脚本输出应立即计算哈希并复制到可信位置:

find /external/ir-dir -type f -print0 |
  sort -z |
  xargs -0 sha256sum > /external/ir-dir/SHA256SUMS

如果采集目录位于被调查主机本地,攻击者仍可能修改它;哈希只能证明“之后读取到的文件与哈希一致”,不能证明文件最初来自可信状态。

4. 内存采集的边界

内存采集可以发现:

  • 注入到进程内存中的代码;
  • 未落盘的恶意脚本;
  • SSH agent、TLS、数据库等进程中的敏感材料;
  • 已删除但仍被进程打开的内容;
  • 反射加载的共享库或异常映射。

但内存采集本身会改变内存,采集工具需要加载驱动、创建进程或通过内核接口读取数据。现代内核、虚拟机和云环境对内存获取的支持差异很大,不能仅凭“Linux 支持”推断某个工具一定可用。

如果业务和证据等级要求较高,应优先选择:

  • 云平台提供的内存快照或取证能力;
  • 虚拟机管理器或带外系统的快照;
  • 与目标内核、架构和发行版明确兼容的采集工具;
  • 可信救援环境。

不要在没有验证兼容性的情况下随意加载第三方内核模块。内核模块会影响系统稳定性,也可能被攻击者利用来隐藏对象。


五、持久化与入口分析:不要只搜恶意文件

攻击者要在重启后继续存在,通常需要持久化;但“没有发现持久化”不等于“没有被入侵”,因为攻击可能只使用短期会话或外部控制器。

1. systemd 持久化

现代发行版大量使用 systemd。应同时检查:

systemctl list-unit-files --all --no-pager
systemctl list-timers --all --no-pager
systemctl --failed --no-pager
find /etc/systemd /run/systemd /usr/lib/systemd /lib/systemd \
  -type f -printf '%TY-%Tm-%Td %TH:%TM:%TS %u:%g %m %p\n' 2>/dev/null

需要进一步查看异常单元的完整内容:

systemctl cat suspicious.service
systemctl show suspicious.service \
  -p FragmentPath -p DropInPaths -p ExecStart -p User -p Environment

systemctl cat 显示的单元可能来自 /etc/systemd/system/run/systemd/system 或发行版提供的目录;systemctl show 能暴露 drop-in 配置和环境变量。仅检查 /etc/systemd/system 会漏掉运行时单元和其他来源。

2. 定时任务和用户级持久化

sudo crontab -l
for u in $(getent passwd | awk -F: '$3 >= 0 {print $1}'); do
  echo "=== $u ==="
  sudo crontab -u "$u" -l 2>/dev/null || true
done

find /etc/cron* /var/spool/cron /var/spool/cron/crontabs \
  -type f -ls 2>/dev/null

systemctl --user list-timers --all --no-pager 2>/dev/null

用户级 systemd 服务的实际位置和可见性取决于用户是否有运行中的 user manager。root 检查不到某些用户会话中的状态,因此需要结合用户会话、loginctl 和文件系统检查。

3. SSH 入口和凭据

OpenSSH 事件分析通常需要同时查看:

  • 认证成功和失败记录;
  • sshd 的启动、配置错误和会话关闭记录;
  • /etc/ssh/sshd_config 及其 Include 文件;
  • 用户的 ~/.ssh/authorized_keys
  • 主机密钥、跳板机和 agent 使用情况;
  • sudosu 和后续命令执行记录。

日志位置取决于发行版和日志服务。例如,Debian 系常见 /var/log/auth.log,RHEL 系常见 /var/log/secure,systemd journal 可能包含同类记录:

sudo journalctl -u ssh.service --since "2025-01-01" --no-pager
sudo journalctl -u sshd.service --since "2025-01-01" --no-pager
sudo journalctl _COMM=sshd --since "2025-01-01" --no-pager

服务单元名不统一,ssh.servicesshd.service 不能硬编码为唯一答案。可以先查:

systemctl list-units --type=service '*ssh*' --all

检查配置时不要只看主文件:

sudo sshd -T
sudo sshd -T -C user=alice,addr=203.0.113.10,host=example
sudo grep -RInE '^(Include|PermitRootLogin|PasswordAuthentication|AuthorizedKeysFile|AllowUsers|AllowGroups|Match)' \
  /etc/ssh/sshd_config /etc/ssh/sshd_config.d 2>/dev/null

sshd -T 输出的是解析后的有效配置,通常比直接阅读配置文件更可靠;-C 会应用连接条件相关的 Match 规则。执行配置检查前,应确认当前 OpenSSH 版本支持所用参数,并避免在未验证语法的情况下重启 SSH:

sudo sshd -t

成功时通常没有输出,非零退出码表示配置错误。修改前应保留现有管理会话和带外通道,因为错误配置可能导致新的 SSH 连接全部失败。OpenSSH 的具体选项和语义应以目标版本的官方手册为准。

4. 文件系统中的常见持久化入口

检查范围至少包括:

  • /etc/ld.so.preload
  • /etc/profile/etc/profile.d、用户 shell 启动文件;
  • /etc/sudoers/etc/sudoers.d
  • setuid/setgid 文件;
  • 内核模块和 DKMS 配置;
  • rc.local、init 脚本;
  • 容器、编排平台和镜像启动配置;
  • 应用自身的插件、钩子和上传目录。

例如,寻找近期改变的 setuid 文件:

sudo find / -xdev -type f \( -perm -4000 -o -perm -2000 \) \
  -printf '%TY-%Tm-%Td %TH:%TM:%TS %u:%g %m %p\n' 2>/dev/null |
  sort

这只能发现当前文件系统中仍存在的对象。攻击者可以恢复原权限、删除文件,或者把恶意代码注入已有可信进程,因此不能把“未发现异常文件”当成清白证明。


六、审计日志和系统日志:它们记录什么,不能证明什么

1. journald、传统日志和 auditd 的差异

三类数据常被混淆:

  • journald:systemd 日志服务,收集内核、服务标准输出和 syslog 等内容;可配置为内存保存或持久化到磁盘。
  • 传统 syslog 文件:例如 /var/log/auth.log/var/log/messages,通常由 rsyslog 或其他守护进程写入。
  • auditd:Linux Audit 子系统的用户空间管理组件,接收内核审计事件并写入审计日志,适合记录身份、系统调用相关行为、文件访问和权限变化等。

它们的可靠性、字段、丢失模式和检索方式不同。日志服务停止、磁盘满、规则缺失、时钟错误和攻击者拥有 root 权限,都可能导致日志不完整。

2. auditd 事件不是“一行一件事”

一个审计事件可能由多条记录组成,共享同一个事件标识,例如:

type=SYSCALL msg=audit(1700000000.123:456): ...
type=EXECVE  msg=audit(1700000000.123:456): ...
type=PATH    msg=audit(1700000000.123:456): ...
type=PROCTITLE msg=audit(1700000000.123:456): ...

其中:

  • 1700000000.123 是事件时间;
  • 456 是该主机审计序列中的事件编号;
  • SYSCALL 说明系统调用上下文;
  • EXECVE 保存执行参数的编码或字段;
  • PATH 描述涉及的路径;
  • PROCTITLE 可能记录进程标题。

必须按事件 ID 聚合后再解释,不能把每一行当成独立操作。

检索示例:

sudo ausearch -m USER_LOGIN,USER_START,EXECVE,AVC \
  --start today --interpret
sudo ausearch -ts 2025-01-15 00:00:00 -te 2025-01-15 23:59:59 \
  -ua 1001 --interpret
sudo aureport --auth --success
sudo aureport --exec --summary

ausearch 的参数和可用事件类型受 audit 工具版本影响;--interpret 会将 UID、系统调用号等转换为更易读的形式,但分析时仍应保留原始记录。

3. auditd 规则的因果边界

例如,规则:

sudo auditctl -w /etc/passwd -p wa -k identity-files

表示对 /etc/passwd 设置写入和属性变化监控,并使用 identity-files 作为检索键。它可以帮助发现文件何时被修改、由哪个进程触发,但有几个边界:

  • 规则加载前发生的事件不会被补记;
  • 审计日志丢失时无法恢复;
  • 规则本身可能被删除、修改或禁用;
  • 只监控 /etc/passwd 不代表监控了所有身份数据库和认证后端;
  • 文件访问审计不能自动证明文件内容是什么;
  • 过宽规则可能造成性能和日志容量压力。

查询:

sudo ausearch -k identity-files --interpret

生产系统应结合 auditd 规则设计、性能评估和合规留存要求。Linux 内核安全文档说明的是内核安全机制和接口边界,而具体发行版的 auditd 默认配置、日志轮换和服务管理仍需以发行版文档为准。

4. “日志里没有记录”不是“没有发生”

缺失记录可能来自:

  • 审计规则未覆盖;
  • journald 使用了 volatile 存储;
  • 日志轮换已覆盖旧文件;
  • 磁盘满导致写入失败;
  • 网络日志接收端不可达;
  • 事件发生在日志服务启动前;
  • 攻击者停止或篡改了日志服务;
  • 系统时间错误,检索范围不正确。

因此应先检查日志系统健康状态和时间范围:

journalctl --disk-usage
journalctl --verify
systemctl status systemd-journald auditd --no-pager
timedatectl
df -h /var /var/log

journalctl --verify 能检查 journal 文件结构,但通过校验不等于内容未被有权限者修改;df 只能说明当前容量,不能证明过去没有丢日志。


七、时间线:把不同时间语义放到同一条轴上

1. Linux 文件时间不是一个时间

常见文件时间包括:

  • mtime:文件内容最后修改时间;
  • ctime:inode 状态最后改变时间,例如权限、所有者、链接数或内容变化;
  • atime:最后访问时间,但可能因挂载选项、文件系统和内核策略而不更新;
  • btime/crtime:创建时间,在部分文件系统和工具中可用,不是所有环境都支持。

查看示例:

stat /path/to/file
stat -c 'path=%n size=%s mode=%A uid=%u gid=%g mtime=%y ctime=%z atime=%x birth=%w' \
  /path/to/file

ctime 不是“创建时间”。攻击者修改权限或所有者时,ctime 可能变化;复制文件时,原始 mtime 可能被保留,而新的 inode 具有不同 ctime

2. 事件时间、观察时间和记录时间

时间线至少应区分:

  • 事件时间:动作实际发生的时间;
  • 记录时间:日志系统写入记录的时间;
  • 观察时间:响应人员执行命令看到状态的时间;
  • 文件时间:文件系统记录的 mtime、ctime 等;
  • 外部时间:防火墙、身份系统、云平台或远程日志中的时间。

若主机时钟偏移 Δ\Delta,主机日志时间 tht_h 与可信外部时间 tet_e 的关系可写成:

teth+Δt_e \approx t_h + \Delta

Δ\Delta 可能随时间变化,不能简单对整台主机永久加一个常数。应检查 NTP/chrony 状态、启动时间和外部日志:

timedatectl
chronyc tracking 2>/dev/null || true
chronyc sources -v 2>/dev/null || true
cat /proc/uptime

3. 时间线的构造方法

一个可复核的时间线应包含以下字段:

字段 含义
normalized_time 转换到统一时区后的时间
source_time 原始数据中的时间
source journal、audit、SSH、文件系统、EDR 等
subject 用户、UID、PID、进程或远端 IP
action 登录、执行、连接、修改、删除
object 文件、服务、端口、目标主机
confidence 证据强度及缺失说明

构造步骤:

  1. 保留所有源文件的原始副本;
  2. 记录每个源文件的 SHA-256;
  3. 解析不同格式的时间,但保留原始行;
  4. 统一时区和时间精度;
  5. 根据 PID、UID、审计事件 ID、SSH 会话和远端 IP 关联事件;
  6. 标记时间矛盾,而不是强行排序;
  7. 把“没有证据”与“证明没有发生”分开记录。

一个简化算例:

  • 10:00:01Z:SSH 日志记录用户 alice203.0.113.10 登录;
  • 10:00:04Z:auditd 记录 UID 1001 执行 /usr/bin/curl
  • 10:00:05Z:文件 /tmp/x 的 mtime 为 10:00:05Z
  • 10:00:07Z:防火墙记录主机向 198.51.100.20:443 发出连接。

这可以形成一条候选链:

SSH 登录执行 curl生成或修改 /tmp/x外连\text{SSH 登录} \rightarrow \text{执行 curl} \rightarrow \text{生成或修改 /tmp/x} \rightarrow \text{外连}

但不能仅凭 mtime 证明 /tmp/x 一定由该次 curl 生成,因为另一个进程可能同时修改了它。需要进一步检查 audit PATH、进程父子关系、文件内容哈希和外部网络日志。

4. 反例:时间线看似合理但结论错误

攻击者可以:

  • 使用 touch 修改 mtime;
  • 通过 faketime 或系统时间设置影响程序记录;
  • 删除日志后恢复部分内容;
  • 利用时区错误制造“错位”的登录和执行记录;
  • 复用合法账号,使用户名看似正常。

所以时间线是事件关联模型,不是自动生成的真相。高可信结论应说明哪些字段直接观察到,哪些关系是推断得到的。


八、证据保全:哈希只能保证完整性的一部分

1. 完整性、真实性和可追溯性

证据保全包含至少三个性质:

  • 完整性:保存后的内容没有被改变;
  • 真实性:能够说明内容来自哪个主机、哪个时间和哪个采集过程;
  • 可追溯性:能够说明谁在何时以什么方式接触、复制、分析过它。

SHA-256 可用于完整性校验:

H=SHA256(D)H = \operatorname{SHA256}(D)

其中 DD 是证据字节序列,HH 是摘要。重新计算得到同一摘要,说明两次输入在密码学碰撞假设下相同;它不能说明第一次采集时 DD 就是可信内容,也不能证明采集过程没有遗漏。

2. 保全记录示例

每个证据对象应有类似记录:

evidence_id: host-a-disk-001
source: /dev/nvme0n1
acquired_at_utc: 2025-01-15T10:20:30.123456Z
collector: responder-07
method: hardware write-blocked imaging
sha256: ...
storage: evidence-store/2025/host-a/
access: read-only

实际环境还应记录:

  • 主机名、实例 ID、磁盘设备和分区;
  • 是否使用只读挂载或硬件写保护;
  • 采集工具及版本;
  • 采集失败、重试和截断信息;
  • 证据转交和访问人员;
  • 存储系统的权限、保留期和审计记录。

3. 磁盘级采集与文件级采集

磁盘级镜像保存分区结构、未分配空间、删除文件残留和文件系统元数据,适合高可信调查,但耗时、占用空间大,并需要足够的外部存储。

文件级采集更快,适合早期响应或容量受限场景,但通常无法恢复删除文件、Slack 空间和完整文件系统上下文。

在可信救援系统中,典型流程可能是:

sudo blockdev --setro /dev/nvme0n1
sudo dd if=/dev/nvme0n1 of=/mnt/evidence/host-a-nvme0n1.img \
  bs=16M iflag=fullblock status=progress conv=noerror,sync
sudo sha256sum /mnt/evidence/host-a-nvme0n1.img \
  | tee /mnt/evidence/host-a-nvme0n1.img.sha256

前提和风险:

  • /mnt/evidence 必须是容量足够的外部存储;
  • blockdev --setro 是内核层面的只读设置,但不能替代硬件写保护;
  • conv=noerror,sync 会在读取错误时继续并填充数据,必须记录错误,否则分析者可能误以为镜像完整;
  • 对正在运行的根磁盘执行镜像可能得到跨时间点的不一致状态;
  • 云盘快照、LVM 快照或存储阵列快照的语义由平台决定,不能自动等价于法证级静态镜像。

若只复制文件,应保留权限、所有者、符号链接和时间:

sudo tar --xattrs --acls --numeric-owner --one-file-system \
  -cpf /mnt/evidence/etc-ssh.tar \
  /etc/ssh /etc/sudoers /etc/sudoers.d
sudo sha256sum /mnt/evidence/etc-ssh.tar

tar 归档的是指定目录,不包含被删除的文件,也不能捕获当时所有进程状态;--one-file-system 可以避免跨入其他挂载点,但也可能漏掉位于独立分区的关键数据。


九、现场分析的安全顺序

分析时应避免在原始证据上直接修改。推荐分层:

  1. 原始证据只读保存;
  2. 制作工作副本;
  3. 在工作副本上解包、挂载和索引;
  4. 输出分析报告和派生证据;
  5. 对派生结果再次计算哈希。

挂载文件系统时应尽量只读:

sudo mount -o ro,noload /dev/mapper/vg-root /mnt/case/root

ro 防止常规写入,noload 对部分日志型文件系统可避免回放日志,但具体支持和语义与文件系统有关。不要在不知道文件系统类型的情况下套用参数:

lsblk -f
blkid /dev/mapper/vg-root

分析可疑二进制时,不要直接在生产主机执行。应使用隔离的沙箱或离线静态分析,并控制网络、权限和共享目录。读取恶意脚本本身通常是低风险的,但执行脚本、加载样本或调用其安装器可能触发破坏和外连。


十、恢复:重建信任,而不是只删除文件

1. 为什么高权限失陷通常倾向重装

当攻击者获得 root 或等价权限后,可能修改:

  • 用户态工具;
  • systemd、SSH 和日志配置;
  • 内核模块;
  • 动态链接器加载路径;
  • 审计规则和日志;
  • 启动过程;
  • 容器运行时和镜像;
  • 管理员的 SSH 密钥与凭据。

此时“执行 rm -f /tmp/malware”不能恢复信任。即使扫描工具没有发现恶意程序,也不能证明系统中没有隐藏后门。

因此,在以下情况中通常应优先重新部署干净系统

  • root 权限已确认或高度怀疑;
  • 启动链、内核或系统工具可能被篡改;
  • 关键日志缺失且无法解释;
  • 无法确定攻击者停留范围;
  • 主机可以由可信镜像和自动化配置快速替换。

2. 重建流程中的证据边界

应先完成必要的取证或保存快照,再重建。恢复数据时分离:

  • 业务数据:数据库、对象、用户上传内容;
  • 系统配置:服务配置、应用参数;
  • 凭据材料:SSH 密钥、API token、数据库密码;
  • 可执行内容:二进制、脚本、容器镜像和插件。

不能把原主机的 /etc、整个 home 目录或应用目录未经审查地复制回新系统,因为其中可能包含持久化机制。恢复过程应从可信来源重建系统包和配置,再逐项导入经过验证的数据。

3. 凭据轮换的范围

如果主机被入侵,应考虑轮换:

  • 主机用户密码;
  • SSH 用户密钥和 authorized_keys
  • 主机密钥是否需要重新生成;
  • 云访问密钥、实例角色或服务账号;
  • 数据库密码;
  • CI/CD token;
  • TLS 私钥;
  • 第三方 API token;
  • 跳板机和 agent 中曾在该主机使用过的凭据。

轮换顺序要考虑依赖关系。先撤销攻击者可能继续使用的凭据,再为恢复系统发放最小权限的新凭据。仅修改主机上的 authorized_keys 不足以处理已经泄露的私钥,因为私钥副本可能存在于管理员电脑、备份、agent 或日志中。

4. 恢复验证

恢复后至少验证:

sudo sshd -t
sudo systemctl --failed --no-pager
sudo ss -lntup
sudo systemctl list-timers --all --no-pager
sudo auditctl -s 2>/dev/null || true
sudo journalctl -b --no-pager -p warning

还应进行:

  • 从可信基线校验系统包和关键配置;
  • 确认只开放预期端口;
  • 验证日志持久化、远程转发和磁盘容量;
  • 验证 auditd 规则实际加载;
  • 验证时间同步;
  • 验证备份可恢复且未被污染;
  • 先灰度接入流量,再逐步扩大;
  • 在一段观察期内提高身份、进程、出站连接和文件变更监控。

恢复不是“服务已启动”。服务能启动只说明进程可以运行,不说明根因已经修复,也不说明凭据没有继续暴露。


十一、常见失败路径及诊断方法

1. 先重启再调查

失败表现:重启后看不到恶意进程和网络连接,临时目录内容消失,内存证据丢失。

原因:关机改变了 MMPPNN,同时可能触发日志轮换、临时文件清理和服务自动恢复。

改进:若没有正在造成严重损害,先完成最小易失数据采集;若必须立即重启,应记录决策原因、时间和业务影响,并保存外部网络与身份日志。

2. 直接删除可疑文件

失败表现:服务暂时恢复,但无法判断文件来源、内容和执行链。

原因:删除破坏了样本,文件仍可能被已运行进程持有,持久化入口也可能在其他位置。

改进:先复制、哈希和记录元数据,再隔离执行路径。若文件正在执行,可以先隔离进程的网络,再决定是否保存 /proc/<pid>/exe 和打开文件列表。

3. 只查 last 和 SSH 失败日志

失败表现:看不到攻击者,误判为“没有登录”。

原因:攻击者可能使用已有会话、服务账号、SSH agent、应用漏洞或本地提权;last 依赖 wtmp,记录也可能缺失或被清理。

改进:把 SSH 日志、sudo 日志、auditd、应用日志、网络流量和云身份日志关联起来。

4. 只看 mtime 判断攻击时间

失败表现:时间线与外部日志冲突,却仍以文件 mtime 为准。

原因:mtime 可被保留、修改或受时钟影响,不一定代表创建或执行时间。

改进:同时使用 ctime、audit PATH、进程执行记录、日志写入时间、文件内容关系和外部时间源,并明确置信度。

5. 在被攻陷主机上安装扫描器

失败表现:扫描器安装失败、结果异常,或安装动作覆盖了重要证据。

原因:软件包下载会产生网络和文件系统事件;恶意主机上的工具和内核可能不可信。

改进:优先使用可信救援系统、离线副本或外部 EDR;必须在线安装时记录安装包哈希、时间和变更,并把它视为现场修改。

6. 把哈希当成真实性证明

失败表现:报告中只有一个 SHA-256 值,却没有采集链路和原始来源。

原因:哈希只能验证输入字节是否一致,不能证明采集内容未被攻击者预先修改,也不能证明采集没有遗漏。

改进:结合只读采集、可信时间、外部存储、访问审计、工具版本和交接记录。


十二、把事件响应能力前移到生产体系

事件发生后能否重建事实,取决于平时是否保存了足够的独立数据源。生产运行手册至少应明确:

  • 哪些主机启用持久化 journal;
  • auditd 记录哪些身份、执行、权限和关键文件事件;
  • 日志发送到哪里,网络中断时如何缓存;
  • 日志保留多久,容量满时如何告警;
  • 主机时钟如何同步,偏差多大时触发告警;
  • 关键主机的可信基线是什么;
  • 如何从负载均衡和网络侧隔离节点;
  • 谁可以批准关机、重装和凭据轮换;
  • 备份如何验证未被攻击者污染;
  • 取证数据如何访问、保留和销毁。

auditd 规则、事件检索、性能和合规留存应单独进行容量设计:记录越多不一定越好,过宽规则可能增加系统负载并造成日志洪峰;记录太少则无法重建关键动作。需要根据威胁模型选择规则,并通过压测、丢失监控和远程留存验证实际效果。

最终,可靠的响应不是依赖某一条神奇命令,而是让以下链条可重复:

告警隔离易失数据保存原始证据保全多源时间线根因与影响判断重建或修复凭据轮换验证和复盘\text{告警} \rightarrow \text{隔离} \rightarrow \text{易失数据保存} \rightarrow \text{原始证据保全} \rightarrow \text{多源时间线} \rightarrow \text{根因与影响判断} \rightarrow \text{重建或修复} \rightarrow \text{凭据轮换} \rightarrow \text{验证和复盘}

其中任何一步都应留下可审查记录。主机恢复上线只代表服务重新提供,不代表事件已经结束;只有当根因、信任关系、证据边界和后续监控都得到处理,响应才算完成。


系列导航与关联阅读

官方资料

本文依据 Linux 内核、systemd 与主流发行版官方文档重新梳理;正文与实验由 WR BLOG 编写。