平台:Linux、Windows Server、macOS
场景:CPU/内存/磁盘/网络异常、挖矿、SSH/RDP 非法登录、反弹 Shell、代理隧道、内网扫描、横向移动、WebShell、DDoS、容器入侵。
使用边界:仅用于自己管理或已获授权的系统。以下示例中的192.0.2.10、203.0.113.50是文档保留地址;12345是示例 PID。所有操作先核对环境。
kill -9 或清空日志:这些操作可能丢失内存证据、破坏时间线、影响业务。但紧急止损优先级可以高于取证完整性。lsof/ss 看到的是当前句柄/连接;历史命令和历史文件操作通常需要预先启用 auditd、Sysmon、EDR、集中日志或堡垒机会话录制。[R] 的命令主要用于读取(但也可能有性能/隐私影响);[M] 会修改系统或安装工具;[D] 会断连、终止进程或影响业务。命令运行时不要把方括号标记复制进去。告警(CPU/内存/网络/磁盘/登录)
├─ 是否为正常负载、批处理、慢查询、GC、备份、发布?
│ └─ 是:按性能故障处理,保留监控基线
└─ 出现未授权登录、未知进程、异常外联、恶意文件或横向访问?
├─ 未确认:低干扰采样 + 日志关联 + 资产核对
└─ 已确认/正在扩散:上游隔离 + 保护证据 + 通报值班
↓
定位入口、账号、进程树、外联、持久化、横向范围、数据外传
↓
可信重建/经过验证的根除 + 修补漏洞 + 轮换凭据
↓
分阶段恢复 + 验证 + 72 小时以上重点观察(时长按风险调整)
| 字段 | 示例/说明 |
|---|---|
| 事件编号与负责人 | INC-2026-001、值班负责人 |
| 时间 | UTC、服务器时区、告警发生时间;核对 NTP 时钟偏差 |
| 主机与资产 | 主机名、IP、实例 ID、云账号、业务、环境、负责人 |
| 初始告警 | CPU 99%、出站流量异常、未知 SSH 登录等 |
| 关键 IOC | 文件哈希、PID、进程路径、域名、远端 IP、账号、计划任务 |
| 已采取动作 | 何时由谁隔离、封禁、停服务、轮换凭据 |
| 影响范围 | 是否涉及其他主机、数据库、密钥、个人信息、备份 |
# [R] 主机整体状态
uptime
nproc
top -b -n 1 | head -35
ps -eo pid,ppid,user,stat,tty,lstart,etime,%cpu,%mem,args --sort=-%cpu | head -30
vmstat 1 5
# 安装了 sysstat 时
mpstat -P ALL 1 5
pidstat -u -r -d 1 5
解释:load average 不等于 CPU 利用率,Linux 还计入不可中断睡眠任务;ps %CPU 是统计口径下的进程 CPU 百分比,不是精确的逐秒瞬时采样;top -H -p PID 可以查看线程。%wa 高先看存储,%st 高考虑虚拟化宿主机争用。
# [R] 找到 PID=12345 后
PID=12345
ps -fp "$PID"
pstree -aps "$PID"
top -H -p "$PID"
readlink -f "/proc/$PID/exe"
readlink -f "/proc/$PID/cwd"
tr '\0' ' ' < "/proc/$PID/cmdline"; echo
cat "/proc/$PID/status"
cat "/proc/$PID/cgroup"
找不到高 CPU 进程? 可能是短生命周期进程、内核线程、中断/软中断、容器内进程、CPU 采样时差或宿主机资源争用。检查 top 的 hi/si/st、pidstat、cat /proc/softirqs、容器指标及宿主机监控;不要因此直接判断为 rootkit。
# [R]
free -h
ps -eo pid,ppid,user,rss,%mem,args --sort=-rss | head -25
vmstat 1 5
swapon --show
cat /proc/meminfo | head -35
sudo journalctl -k --since '24 hours ago' | grep -Ei 'oom|out of memory|killed process'
# 指定 PID 的聚合内存信息(需权限,某些内核可能不存在)
sudo cat /proc/12345/smaps_rollup
不要把 Linux 页缓存误判为内存泄漏。注意 available、Swap 进出、RSS/PSS、OOM 记录。容器环境还应检查 cgroup 内存限制和 OOMKilled。
# [R]
df -hT
df -i
lsblk -f
vmstat 1 5
# sysstat 工具包
iostat -xz 1 5
pidstat -d 1 5
sudo lsof -nP +L1
sudo journalctl -k --since '24 hours ago' | tail -100
lsof +L1 可发现已经删除但仍被打开的文件(包括日志或可疑程序);不能单凭这一点认定恶意。I/O 飙高也可能来自备份、数据库刷盘、日志轮转。
# [R]
PID=12345
sudo lsof -nP -p "$PID"
sudo ls -lah "/proc/$PID/fd"
sudo readlink "/proc/$PID/exe"
sudo readlink "/proc/$PID/cwd"
sudo sha256sum "/proc/$PID/exe"
sudo stat "/proc/$PID/exe"
局限:lsof 不能证明进程过去读取、修改或删除过哪些文件。/proc/PID/exe 可能指向带 (deleted) 的可执行文件;PID 可能被系统复用,执行操作前重新核对进程启动时间、路径和父进程。
# [R-高干扰] strace 附加会短暂暂停进程并增加开销,只在批准后短时使用
sudo timeout 10 strace -ff -tt -p 12345 -e trace=%file \
-o /root/incident-strace
# 读写系统调用:可能记录敏感数据/影响性能
sudo timeout 10 strace -ff -tt -p 12345 \
-e trace=read,write,pread64,pwrite64,openat,unlinkat,renameat \
-o /root/incident-rw
-ff 会为不同被跟踪进程产生独立输出文件;不能恢复附加前的历史。生产优先使用预先部署的 auditd/eBPF/EDR。strace 本身可能被系统 ptrace 安全策略阻止。
# [R] 监听端口 / 全部连接 / 已建立连接
sudo ss -lntup
sudo ss -antp
sudo ss -anup
sudo ss -ntp state established
sudo ss -ntp state syn-sent
sudo lsof -nP -a -p 12345 -i
sudo lsof -nP -iTCP -sTCP:LISTEN
# SSH 的服务端连接(SSH 可能不在 22 端口)
sudo ss -ntp '( sport = :22 )'
ss 的 -p 在权限不足、进程退出、容器网络命名空间或内核隐藏等情况下可能看不到进程。UDP 通常没有 TCP 意义上的 ESTABLISHED 状态;UDP 的“连接”可能只是应用指定默认远端地址。
# [R] 需预装工具,命令中的 eth0 换成实际网卡
ip -br link
sudo nethogs eth0 # 按进程显示流量,部分环境归属不完整
sudo iftop -i eth0 -nP # 按远端主机/端口看流量,不等于按 PID
sar -n DEV 1 5 # 网卡吞吐(需 sysstat)
ip -s link show eth0
没有 nethogs 时:用 ss -ntp/lsof -i 将连接关联到 PID,配合 tcpdump、防火墙/云流日志判断哪条连接流量异常。高流量可能来自正常备份、对象存储同步、视频服务或数据迁移。
# [R-有开销] 最多 10000 包或 60 秒,文件可能包含凭据或业务数据
sudo timeout 60 tcpdump -i eth0 -nn -s 0 -c 10000 \
-w /root/incident-network.pcap
# 特定目标
sudo tcpdump -i eth0 -nn 'host 203.0.113.50'
# 内网扫描线索:只在本机被动观察
sudo tcpdump -i eth0 -nn 'net 10.0.0.0/8 and tcp'
SSH/HTTPS 抓包一般不能直接看到加密会话中的命令内容。PCAP 要限制权限、加密存储并遵守数据保护要求。
# [R]
who -a
w
last -ai | head -50
sudo lastb -ai | head -50 # 若系统提供失败登录数据库
sudo ss -ntp '( sport = :22 )'
ps -ef --forest | grep '[s]shd'
# systemd 服务名依发行版可能是 ssh 或 sshd
sudo journalctl -u ssh --since '24 hours ago' --no-pager
sudo journalctl -u sshd --since '24 hours ago' --no-pager
# Debian/Ubuntu(若存在传统文件日志)
sudo grep -Ei 'Accepted|Failed|Invalid user|session opened' /var/log/auth.log
# RHEL/Rocky(若存在传统文件日志)
sudo grep -Ei 'Accepted|Failed|Invalid user|session opened' /var/log/secure
注意:who/w 可能看不到非交互式 SSH、仅端口转发或无 TTY 会话。lastb 依赖日志数据库,可能不存在。集中日志/堡垒机记录通常比受害主机上的日志更可信。
# [R] pts/2 仅为示例,请先从 w/ps 确认
ps -t pts/2 -o pid,ppid,user,tty,lstart,args
pstree -aps 12345
ps -eo pid,ppid,user,tty,lstart,args --forest
不要使用 pkill sshd、killall sshd 或直接停止 SSH 服务来处理单个攻击会话;这样会踢掉合法管理员,甚至失去救援通道。
| 证据来源 | 能看到什么 | 关键限制 |
|---|---|---|
ps、pstree、/proc/PID/cmdline |
当前进程及参数 | 短命令可能已退出,命令行可伪装 |
.bash_history、.zsh_history |
部分交互命令 | 可能未写盘、被禁用或篡改;非完整审计 |
auditd execve |
规则生效后的进程执行 | 不能恢复过去;Shell 内建命令不一定有独立 execve |
| Sysmon for Linux / EDR / eBPF | 进程、网络、文件关联 | 依赖预先安装和规则配置 |
| 堡垒机录屏/会话审计 | 通过堡垒机的操作 | 绕过堡垒机的连接不在其中 |
| PCAP | 会话端点、时间、流量特征 | SSH 加密内容无法直接解读 |
# [R] 历史文件(可能包含机密)
sudo stat /root/.bash_history
sudo tail -100 /root/.bash_history
# [M] 临时开启 auditd execve 审计(需先评估日志量和性能)
sudo auditctl -a always,exit -F arch=b64 -S execve -S execveat -k ir_exec
# [R] 查看规则启用后的事件
sudo ausearch -k ir_exec -i
sudo aureport -x --summary
某些系统没有 execveat 或不支持对应审计规则,须先检查 auditctl -l 与返回码;32 位兼容程序需单独配置 b32 规则。应为审计日志配置远程转发和容量限制。临时规则会改变系统状态,并不代表自动获得完整的历史命令记录。
首选:云安全组/上游 ACL/EDR 隔离恶意源 IP 或受害主机,确保可信管理通道仍可访问;检查 VPN、堡垒机、NAT 和 IPv6 入口。
# [R] 确认当前 SSH 连接及其两端 IP/端口
sudo ss -ntp '( sport = :22 )'
# [R] 查看现有 nftables 链(链名未必是 inet filter input)
sudo nft list ruleset
# [D] 仅当该链确实存在且顺序合适时,示例阻断来源的新入站 SSH 流量
sudo nft insert rule inet filter input ip saddr 203.0.113.50 tcp dport 22 drop
注意:如果已有连接在更早的 ct state established accept 规则处放行,封禁规则可能无效;如果 SSH 端口不是 22 或存在 IPv6、其他入口,也要分别处理。生产优先通过上游防火墙或 EDR 隔离,检查实际流量是否中断。
# [D] Linux ss -K 支持的环境中,可按准确的四元组尝试终止一条 TCP 连接
# 先用 ss 核对本地服务器 IP:22 和远端客户端 IP:临时端口
sudo ss -K src 192.0.2.10 sport = :22 dst 203.0.113.50 dport = :54321
ss -K 的可用性取决于内核/工具,可能返回不支持或未匹配。不要在未核对四元组时执行。必要时针对确认的 SSH 子会话进程终止,不要杀主 sshd 守护进程。切断连接并不等于撤销攻击者凭据。
# [R]
sudo sshd -T | grep -Ei 'permitrootlogin|passwordauthentication|pubkeyauthentication|allowusers|authorizedkeysfile'
sudo find /root /home -type f -name authorized_keys -print 2>/dev/null
sudo getent passwd
sudo getent group sudo
sudo getent group wheel
sudo find /etc/ssh -type f -mtime -14 -ls
核对 authorized_keys、用户新增、sudoers、sshd_config、SSH CA/证书、PAM 配置及其他凭据;保存证据后撤销未授权公钥、轮换相关私钥/密码/token,并检查相同凭据是否在其他服务器使用。
# [R]
ps -eo pid,ppid,user,lstart,etime,%cpu,%mem,args --sort=-%cpu | head -30
sudo lsof -nP -a -p 12345 -i
sudo readlink /proc/12345/exe
sudo sha256sum /proc/12345/exe
sudo ls -lah /proc/12345/fd
可疑特征:未知程序持续高 CPU、与未知外部节点长期通信、进程来自临时目录、进程名伪装、自动恢复。这些都是线索而非单独的定罪证据。特别关注 (deleted) 可执行文件、异常父进程、容器进程、恶意配置与真实业务基线的差异。
# [R] 系统服务/计时器
systemctl list-units --type=service --all
systemctl list-unit-files --type=service
systemctl list-timers --all
sudo find /etc/systemd/system /usr/local/lib/systemd/system -type f -mtime -14 -ls 2>/dev/null
# root 与系统级 cron
sudo crontab -l
sudo ls -lah /etc/cron.d /etc/cron.daily /etc/cron.hourly /etc/crontab
# 各用户 cron(需要 root;逐一确认权限)
while IFS=: read -r u _; do echo "===== $u ====="; sudo crontab -u "$u" -l 2>/dev/null; done < /etc/passwd
# 临时目录中新近文件
sudo find /tmp /var/tmp /dev/shm -xdev -type f -mtime -7 -ls
# 最近新增/修改的 SSH 公钥和启动配置
sudo find /root /home /etc -type f \( -name authorized_keys -o -name '*.service' -o -name '*.timer' \) -mtime -14 -ls 2>/dev/null
补充排查:/etc/rc.local、用户 systemd、Shell profile、/etc/ld.so.preload、sudoers、PAM、容器启动策略、Kubernetes DaemonSet/CronJob。不要只搜 xmrig、frpc 等名称:恶意程序可任意改名。
# [R]
sudo ss -ntp state established
sudo lsof -nP -i
ps -eo pid,ppid,user,lstart,args --forest | grep -Ei 'ssh|socat|frp|chisel|cloudflared|ngrok|gost|python|bash|sh'
systemctl list-units --type=service --all | grep -Ei 'tunnel|proxy|frp|cloudflared'
重点识别:不应存在的公网出站长连接;Shell 进程继承网络套接字;ssh -R、ssh -D 端口转发;frpc、chisel、socat 等未登记的远程接入工具。这些工具本身也有合法用途,必须结合授权清单与业务行为判断。
# [R] 确认进程
ps -fp 12345
pstree -aps 12345
# [D] 确认后先正常终止,必要时强制终止
sudo kill -TERM 12345
# 复查 PID 与进程启动时间,确认未退出后才考虑:
sudo kill -KILL 12345
# [D] 如果确定为恶意 systemd 服务:
sudo systemctl stop suspicious.service
kill -9 无法杀死处于不可中断睡眠(D 状态)的进程;进程可能被服务管理器拉起,或者 PID 被复用。对容器工作负载应通过编排系统控制,而不是在宿主机上盲目 kill。
# [R] 查看大量 SYN-SENT 和到内网的连接
sudo ss -ntp state syn-sent
sudo ss -antp
sudo lsof -nP -i
# [R-有开销] 被动捕获 30 秒内网 TCP 连接,替换实际网卡/网段
sudo timeout 30 tcpdump -i eth0 -nn -s 96 -c 5000 \
'net 10.0.0.0/8 and tcp' -w /root/incident-internal.pcap
不要仅凭连接数量认定扫描:服务发现、健康检查、监控、备份也可能产生大量连接。结合防火墙/VPC Flow Logs、DNS、EDR、业务资产清单判断“同一来源短时间访问大量不同目标 IP/端口”。
处理顺序:隔离起点主机 → 阻断到敏感网段的横向路径 → 从可信网络/EDR 查询接触过的资产 → 按证据逐台隔离 → 轮换共享凭据 → 修复漏洞与重建 → 分阶段恢复。
| 现象 | 可能原因 | 优先位置 |
|---|---|---|
| 公网入口带宽打满、丢包 | UDP/TCP 大流量攻击 | 运营商、云高防、清洗中心 |
| SYN_RECV 异常、握手失败 | SYN Flood 或网络故障 | 上游清洗、LB、SYN 防护 |
| HTTP QPS 激增、相似 URL 高频 | HTTP Flood、爬虫或活动流量 | CDN/WAF/网关 |
| 活跃连接耗尽 | 慢连接/连接泄漏 | LB、反向代理超时和连接限制 |
| MySQL/Redis 负载飙升 | 应用接口放大、缓存击穿、重试风暴 | API 限流、熔断、缓存、DB 限流 |
# [R]
uptime
sudo ss -s
sudo ss -ant state syn-recv
ip -s link show eth0
sar -n DEV 1 5
nstat -az
# Nginx:按日志实际格式调整;代理环境不能把代理 IP 当成真实用户 IP
sudo tail -n 300 /var/log/nginx/access.log
sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -20
sudo awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -20
重要:ss 在巨量连接时也可能消耗资源;攻击中优先查看云监控、LB/WAF/NetFlow,而不是在已过载的主机上频繁执行全量枚举。若上游带宽已满,本机 iptables/nftables 无法恢复被占满的外部链路。
http {
limit_req_zone $binary_remote_addr zone=per_ip:10m rate=10r/s;
server {
listen 80;
location /api/ {
limit_req zone=per_ip burst=20 nodelay;
proxy_pass http://backend;
}
}
}
# [R] 先检查语法;[M] 再经变更审批重载
sudo nginx -t
sudo systemctl reload nginx
真实环境应将配置合并到已有 http/server 块,不能重复嵌套;设置可信代理和真实客户端 IP,避免误伤同 NAT 用户;同时考虑账号/API Key、路径、会话等限流维度。限流不能替代 CDN/WAF/高防。
# [R] Redis(使用授权账号与 TLS,避免把密码直接写在命令行)
redis-cli INFO clients
redis-cli INFO stats
redis-cli SLOWLOG GET 20
-- [R] MySQL(需要相应权限)
SHOW FULL PROCESSLIST;
SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Max_used_connections';
优先策略:WAF/网关限流 → 应用并发限制和请求超时 → 下游连接池上限 → 熔断与降级 → 限制重试次数/退避与抖动 → 队列背压 → 缓存热点保护。检查 Redis/MySQL/Kafka 是否被暴露公网;避免在故障时盲目重启数据库、清空缓存或调大所有连接池。
使用管理员 PowerShell。
CPU属性是累计处理器时间(秒),不是实时 CPU 百分比;WorkingSet64是工作集内存,不等于进程全部提交内存。
# [R] 按累计 CPU 时间排序
Get-Process | Sort-Object CPU -Descending |
Select-Object -First 20 Name,Id,CPU,WorkingSet64
# [R] 按工作集排序
Get-Process | Sort-Object WorkingSet64 -Descending |
Select-Object -First 20 Name,Id,WorkingSet64,Path
# [R] 进程路径、命令行、父 PID、创建时间
Get-CimInstance Win32_Process -Filter 'ProcessId=12345' |
Select-Object ProcessId,ParentProcessId,ExecutablePath,CommandLine,CreationDate
# [R] 实时 CPU 计数器;多核环境数值可超过 100%,按核心数解释
Get-Counter '\Process(*)\% Processor Time' -SampleInterval 1 -MaxSamples 3
# [R] 性能监视器 / 资源监视器
perfmon.exe
resmon.exe
# [R]
Get-NetTCPConnection -State Listen
Get-NetTCPConnection -State Established
Get-NetTCPConnection -OwningProcess 12345
Get-NetUDPEndpoint
Get-NetAdapterStatistics
# CMD 兼容命令
netstat -abno
tasklist /FI 'PID eq 12345'
Get-NetAdapterStatistics 是网卡级流量,不是 PID 流量。可通过资源监视器查看进程网络活动;长期准确归因需要 EDR/ETW/网络监控。部分系统进程的路径或命令行受权限保护。
# [R] 安装可信来源的 Sysinternals Handle 后
.\handle64.exe -p 12345
# [R] 文件签名和哈希
Get-AuthenticodeSignature 'C:\Path\suspect.exe'
Get-FileHash 'C:\Path\suspect.exe' -Algorithm SHA256
Handle 的结果是当前句柄,不是历史操作。签名有效也不等于程序可信。
# [R] 当前远程会话
quser
qwinsta
# [R] 成功/失败登录
Get-WinEvent -FilterHashtable @{LogName='Security';Id=4624;StartTime=(Get-Date).AddHours(-24)} -MaxEvents 100
Get-WinEvent -FilterHashtable @{LogName='Security';Id=4625;StartTime=(Get-Date).AddHours(-24)} -MaxEvents 100
# [R] 进程创建(需要事先开启审计及命令行记录策略)
Get-WinEvent -FilterHashtable @{LogName='Security';Id=4688;StartTime=(Get-Date).AddHours(-24)} -MaxEvents 100
# [R] PowerShell 脚本块日志(事先开启策略)
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational';Id=4104;StartTime=(Get-Date).AddHours(-24)} -MaxEvents 100
# [R] PowerShell 模块日志(需启用)
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational';Id=4103;StartTime=(Get-Date).AddHours(-24)} -MaxEvents 100
# [R] Sysmon(需要预先安装)
Get-WinEvent -LogName 'Microsoft-Windows-Sysmon/Operational' -MaxEvents 100
| 事件 | 解释 |
|---|---|
| Security 4624 / 4625 | 登录成功 / 失败;4624 Type 10 常见 RDP,Type 3 网络登录 |
| Security 4688 | 新进程创建(是否含命令行取决于策略) |
| Security 4698 | 创建计划任务 |
| Security 4720 | 创建本地/域用户 |
| Security 1102 | 安全日志被清除 |
| System 7045 | 安装新服务 |
| PowerShell 4103 / 4104 | 模块日志 / 脚本块日志(依配置) |
| Sysmon 1 / 3 / 11 / 22 | 进程创建 / 网络连接 / 文件创建 / DNS 查询(依配置) |
还要检查 TerminalServices 相关 Operational 日志、WinRM、WMI-Activity、TaskScheduler、Defender、域控登录与 Kerberos 事件。日志缺失不等于攻击不存在。
# [M/D] 阻断指定来源入站;注意可能影响合法共享 NAT 用户
New-NetFirewallRule -DisplayName 'IR Block Suspicious IP' `
-Direction Inbound -RemoteAddress 203.0.113.50 -Action Block
# [M/D] 阻断访问指定远端 IP
New-NetFirewallRule -DisplayName 'IR Block Outbound IP' `
-Direction Outbound -RemoteAddress 203.0.113.50 -Action Block
# [R] 查看规则
Get-NetFirewallRule -DisplayName 'IR Block*'
# [D] 仅在确认恶意 PID 后终止
Stop-Process -Id 12345 -Force
# [D] 核对 quser 的会话 ID 后注销指定会话(示例 3)
logoff 3
防火墙新规则不保证立刻断开全部已有会话;应在网络设备/EDR 核实连接已中止。logoff 可能导致未保存的工作丢失。不要把所有 svchost.exe、powershell.exe、w3wp.exe 一律认定恶意。
# [R]
Get-ScheduledTask
Get-CimInstance Win32_Service | Select-Object Name,State,StartMode,PathName
Get-CimInstance Win32_StartupCommand
Get-ItemProperty 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Run'
Get-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Run'
Get-LocalUser
Get-LocalGroupMember -Group 'Administrators'
Get-SmbSession
Get-SmbOpenFile
再检查:WMI 永久事件订阅、WinRM、远程服务、RDP 登录、SMB 访问、域管理员与服务账号、GPO、计划任务、证书、Defender 排除项。域环境调查不能只在单台 Windows Server 上完成。
macOS 版本差异较大;System Integrity Protection (SIP)、TCC、隐私权限可能限制调查。不要为了临时排查随意关闭 SIP 或 Gatekeeper。
# [R]
top -o cpu
top -o mem
ps aux | sort -nrk 3 | head -20
ps aux | sort -nrk 4 | head -20
vm_stat
ps -p 12345 -o pid,ppid,user,lstart,command
# [R]
sudo lsof -nP -p 12345
sudo lsof -nP -i
sudo lsof -nP -iTCP -sTCP:LISTEN
sudo lsof -nP -iTCP -sTCP:ESTABLISHED
sudo lsof -nP -iUDP
nettop
netstat -an
shasum -a 256 /path/to/suspect
codesign -dv --verbose=4 /path/to/suspect
codesign --verify --verbose=4 /path/to/suspect
nettop 是实时流量观察工具,不保证对每个连接都能准确归因。macOS 无 Linux /proc/PID/fd 接口;不要照搬 Linux 的 /proc、ss、systemctl、auditctl 命令。
# [R]
who
w
sudo lsof -nP -iTCP:22
ps aux | grep '[s]shd'
sudo log show --last 2h --style compact --predicate 'process == "sshd"'
sudo log stream --style compact --predicate 'process == "sshd"'
ls -lah /Library/LaunchAgents/
ls -lah /Library/LaunchDaemons/
ls -lah ~/Library/LaunchAgents/
sudo launchctl print system
launchctl print "gui/$(id -u)"
plutil -p /Library/LaunchDaemons/suspicious.plist
查看 ProgramArguments、KeepAlive、RunAtLoad、文件签名、实际可执行路径及所属账号;检查 Login Items、配置描述文件、远程管理设置和 SSH 公钥。统一日志可能因隐私过滤、日志保留期限或权限而缺失信息。
优先通过网络侧 ACL/MDM/EDR 隔离;PF 配置必须先检查现有规则、anchor、状态和回滚通道,不要直接覆盖 /etc/pf.conf。
# [R]
sudo pfctl -s info
sudo pfctl -sr
sudo pfctl -ss
# [D] 确认后停止恶意进程
sudo kill -TERM 12345
# 复查后必要时:
sudo kill -KILL 12345
launchd 管理的恶意任务应先保存 plist 与日志,确认所属 system/gui 域、标签,再使用对应 launchctl bootout 操作;不要批量停用系统服务。
# [R] 在 Docker 宿主机执行
docker ps --no-trunc
docker stats --no-stream
docker inspect CONTAINER_ID
docker logs --since 2h CONTAINER_ID
# [R] 宿主机上的容器进程
docker top CONTAINER_ID
调查容器镜像来源、启动命令、挂载卷、特权模式、Docker Socket、环境变量中的密钥、异常出站连接。不要只在容器里杀恶意进程;确认是否通过编排系统重新启动。高权限容器逃逸迹象要扩大到宿主机。
# [R] 使用有权限的管理终端
kubectl get pods -A -o wide
kubectl get events -A --sort-by=.lastTimestamp
kubectl top pods -A
kubectl get cronjobs -A
kubectl get daemonsets -A
kubectl get networkpolicies -A
kubectl describe pod POD_NAME -n NAMESPACE
kubectl logs POD_NAME -n NAMESPACE --since=2h
重点检查:ServiceAccount 权限、RBAC、K8s API 审计、节点登录、镜像供应链、特权 Pod、hostPath、容器网络策略、异常 Job/CronJob。K8s kubectl logs 并非不可篡改的完整审计记录。
说明:此脚本仅做常见系统状态采集,不杀进程、不修改防火墙、不安装软件、不执行内网扫描。它仍会在本机写文件、读取可能敏感的日志,不能替代法证级内存/磁盘镜像。优先通过可信控制台执行;root 失陷时本机输出可能被伪造。
保存为 incident_collect.sh:
#!/usr/bin/env bash
set -u
umask 077
# 优先使用独立挂载的可信证据卷;默认 /root(需 root 权限)
BASE="${IR_OUTPUT_DIR:-/root/incident-$(date -u +%Y%m%dT%H%M%SZ)}"
mkdir -p -- "$BASE" || exit 1
chmod 700 "$BASE"
capture() {
local name="$1"
shift
{
printf 'UTC: %s\n' "$(date -u --iso-8601=seconds)"
printf 'Command:'; printf ' %q' "$@"; printf '\n'
"$@"
} > "$BASE/$name.txt" 2>&1 || true
}
capture host hostnamectl
capture uname uname -a
capture time date -u
capture uptime uptime
capture who who -a
capture login_history last -ai
capture processes ps auxwwf
capture process_details ps -eo pid,ppid,user,tty,lstart,etime,%cpu,%mem,args
capture tcp_udp ss -antup
capture listening ss -lntup
capture memory free -h
capture disk df -hT
capture mounts mount
capture interfaces ip -br address
capture routes ip route
capture services systemctl list-units --type=service --all
capture timers systemctl list-timers --all
capture root_cron crontab -l
capture kernel_logs journalctl -k --since '24 hours ago' --no-pager
capture auth_logs journalctl --since '24 hours ago' --no-pager -u ssh -u sshd
capture firewall nft list ruleset
# 限定常见临时目录,避免递归遍历全盘或挂载点
find /tmp /var/tmp /dev/shm -xdev -type f -mtime -7 -ls \
> "$BASE/recent_tmp_files.txt" 2>&1 || true
find /etc/systemd/system -type f -mtime -14 -ls \
> "$BASE/recent_services.txt" 2>&1 || true
# 为全部采集文件生成哈希清单
(
cd "$BASE" || exit 1
find . -type f ! -name SHA256SUMS -print0 |
sort -z |
xargs -0 -r sha256sum > SHA256SUMS
)
printf 'Collection complete: %s\n' "$BASE"
执行:
# [M] 在确认可信来源与授权后执行
sudo bash incident_collect.sh
# 或指定独立证据卷(目录必须存在、空间充足且可信)
sudo IR_OUTPUT_DIR=/mnt/ir-evidence/incident-001 bash incident_collect.sh
脚本适用于常见 systemd Linux 环境。没有 hostnamectl、journalctl、nft 等命令时,相应文本文件会包含错误信息,其他步骤继续执行。某些系统 xargs -r 不可用;该脚本不适用于原样在 macOS 上执行。保存输出后应立即传输至可信证据存储、限制访问、记录采集人/时间并校验哈希。若需司法级证据,请采用合规的取证流程与工具。
uptime、top、pidstat 判断是 CPU 计算、内核中断还是 I/O 等待。ps --sort=-%cpu 找 PID;查父进程、启动时间、可执行文件、哈希、打开文件。ss/lsof/nethogs 查外联、异常代理和矿池通信线索。who/w/ss/journalctl 关联来源 IP、用户、TTY、登录时间、PID。.bash_history 只能辅助。authorized_keys、sudoers、PAM、cron、systemd。kill -9;保存每次出现的 PID、PPID、启动时间和哈希。Restart=、cron、用户 systemd、容器 restart policy、K8s 控制器。| 目标 | Linux | Windows Server | macOS |
|---|---|---|---|
| CPU | top、ps、pidstat |
Get-Process、Get-Counter |
top -o cpu |
| 内存 | free -h、smaps_rollup |
Get-Process、PerfMon |
vm_stat |
| 磁盘 | df、iostat、pidstat -d |
PerfMon、资源监视器 | iostat、df |
| 文件句柄 | lsof -p PID、/proc/PID/fd |
Sysinternals Handle | lsof -p PID |
| TCP/UDP | ss -antup |
Get-NetTCPConnection、Get-NetUDPEndpoint |
lsof -i、netstat |
| 按进程流量 | nethogs |
资源监视器/EDR | nettop |
| 当前登录 | who、w |
quser、qwinsta |
who、w |
| 历史登录 | last、journalctl |
4624/4625、RDP 日志 | log show |
| 执行命令 | auditd/EDR/堡垒机 | 4688/Sysmon/4104 | EDR/统一日志(有限) |
| 自启动 | cron/systemd | 计划任务/服务/注册表/WMI | launchd/Login Items |
| 阻断 | 上游 ACL/nftables | 上游 ACL/Windows Firewall | 上游 ACL/PF |
| 终止进程 | kill -TERM PID |
Stop-Process |
kill -TERM PID |
kill -9只会结束一个进程,不会结束一次入侵。完整闭环:确认 → 取证 → 隔离 → 定界 → 根除/可信重建 → 凭据轮换 → 恢复 → 监控 → 复盘。
参考权威文档(核对具体系统版本):
man ps、man ss、man lsof、man auditctl、man ausearch、man nft、man strace。log、launchctl、pfctl、codesign。limit_req_zone、limit_req;Redis 官方 INFO/SLOWLOG;MySQL 官方 SHOW PROCESSLIST。版本注意:命令在不同发行版、内核、Windows/macOS 版本及权限策略下可能不可用;在生产执行变更前先核对 --help/手册、现有配置、变更窗口与回滚通道。本文不承诺任何单一命令能证明系统已无后门。