一、概述
把服务器和办公 PC 当成同一类检材,是这条线上最容易犯、代价也最大的错误。
差别不在硬件,在证据生存条件。办公 PC 通常已关机封存,磁盘是静止的,你可以慢慢分析。
服务器通常还开着。
Nginx 正在写 access.log,logrotate 每晚轮转,journald 在滚动,MySQL 的 binlog 正在被写满并删除。你每多等一小时,证据就少一小时。 这就是服务器取证与离线 PC 取证最根本的差别:服务器取证是一场和日志轮转的赛跑。
第二个差不要在信任模型。办公 PC 上非管理员账户基本动不了系统目录;服务器上则不然——/www/wwwroot 站点目录对 Web 用户可写(业务硬需求),管理面板一个 Web 口令就等价于 root,失败成本从"单机影响"变成"一个上传点沦陷整机再横向内网"。
这直接决定了证据分布:服务器上最有价值的痕迹,绝大多数不在系统日志里,而在网站目录和 Web 访问日志里。 涉 webshell、挖矿、篡改网站的案件,第一现场永远是站点根目录和 access.log,而不是 auth.log。
在取证流程中的位置:本篇是服务器场景的入口与导航,属于采集环节的前置判定层。它不解析任何东西,只回答三件事:证据在哪里、活得多久、该按什么顺序抢。深入分析见 宝塔面板取证 与 宝塔新版加密数据解密,Web 服务器层见 Nginx 与 Apache 配置取证,后门层见 网站目录与 WebShell 检测。Linux 通用痕迹见 Linux 取证工件地图,本篇不重复。
涉及的证据形态(Web 环境分散在三处,宝塔是国内最主流的,下面三组路径都要查):
| 路径 |
内容 |
/www/wwwroot/<site>/ |
宝塔站点根目录(对 Web 用户可写) |
/www/server/panel/data/ 与 logs/ |
面板数据库配置与操作日志 |
/www/server/panel/vhost/ |
宝塔生成的站点配置 |
/www/server/nginx/conf/ |
宝塔自编译的 Nginx(不是 /etc/nginx) |
/www/wwwlogs/ |
宝塔的网站日志目录(不是 /var/log/nginx) |
/www/backup/ |
宝塔自动备份(站点 + 数据库) |
/var/www/、/etc/nginx/、/var/log/nginx/ |
源包安装 / 发行版环境 |
/etc/cron.d/、/var/spool/cron/crontabs/ |
计划任务(面板也能写) |
/root/.bash_history、/home/*/.bash_history |
面板 / SSH 操作留下的命令历史 |
mysql-bin.0000xx、general_log |
binlog 与查询日志,拖库行为的痕迹几乎必然在此 |
⚠️ 最容易漏的三个目录:/www/backup/(勒索事件中可能含被加密前的原始数据);/www/wwwlogs/(去 /var/log/nginx 找会得到"没有访问日志"的错误结论);/www/server/nginx/conf/(宝塔的 Nginx 是自己编译的)。
服务器证据为什么"活得短":logrotate 通常 rotate 7~14,第 N+1 次轮转时最老那份被删除;journald 的 SystemMaxUse 常见 200M~4G,超出后丢弃最旧的日志(不是停止写入);MySQL binlog 的 expire_logs_days 默认 10 天,到期自动删除。推论:"日志被覆盖"是常态而非异常,不能假设日志覆盖了入侵全程;而"发现覆盖"本身就是结论的一部分,它说明攻击者或管理员做过什么,必须写进报告,不能只写"未发现相关记录"。
服务仍在运行意味着什么(处置顺序是硬性的):
① 抢占式固定(分钟级)——内存镜像 + 关键日志定向复制 + 远程备份/只读快照。
② 网络层隔离(不是关机)——防火墙限流或断网,保留 SSH 通道给取证人员。
③ 决定是否停服——能冻结证据但会中断业务,需委托方书面同意。
④ 全盘镜像 → ⑤ 离线深度分析。
关键判断:先固定后隔离,先隔离后停服,停服需授权。 直接拔电虽然"最安全地冻结了现场",但会销毁内存证据和 tmpfs 内容,对服务器往往是净损失。
服务器上证据散在哪些位置、哪些还活着、现场该怎么处置、按什么优先级往下查。
具体某个 WebShell 怎么工作(那是后门层的内容);日志被覆盖掉的时段发生了什么(只能写"未覆盖",不能写"未发生");面板里的加密配置怎么解(见 宝塔新版加密数据解密);"access.log 里没有"不等于"没被访问"——日志可能被清、被轮转覆盖、或攻击者走了未记录日志的路径。
内容边界:本文用于已获得合法授权的取证场景,所有命令面向已授权的目标主机或已制作的只读镜像。目标是发现与固定证据,不提供任何入侵手段。检测到 WebShell、异常账户、可疑计划任务时,写的是如何识别与如何排除误报。
读者前提:需要 Linux 取证工件地图 的通用痕迹基础、取证流程与原则 的处置纪律,以及基本的 Web 服务架构认知。如果主机还在线,请先读 2.2 服务仍在运行意味着什么 与 3.1 第 0 步——这一步的顺序错了,后面所有分析都是在分析一个已经变过的现场。
二、核心原理
2.1 服务器证据为什么"活得短"
服务器上的记录不是"写下来就永久保存",而是走一条有寿命的流水线:
Nginx 写 access.log ──┐
应用写业务日志 ───────┼──> logrotate 按 size/天 轮转 ──> 压缩归档 .gz
journald 写 journal ──┘ │ 保留 N 份
│ 超过保留数 → 覆盖/删除
binlog / 慢日志 ──> 写满 → 按 expire_logs_days 清理
临时文件 ──> systemd-tmpfiles 按 age 清理
| 机制 |
默认留存量级 |
丢失触发点 |
logrotate 归档份数 |
通常 rotate 7~rotate 14(天或周) |
第 N+1 次轮转时最老那份被删除 |
| journald 持久化上限 |
SystemMaxUse 常见 200M~4G |
超出后丢弃最旧的日志(不是停止写入) |
| MySQL binlog |
expire_logs_days 默认 10 天 |
到期自动删除 |
/var/log/ 下 *.1、*.gz |
同上 |
覆盖或删除 |
取证推论:①"日志被覆盖"是常态而非异常,不能假设日志覆盖了入侵全程;②入侵若发生在半年前,access.log 可能只剩最近两周;③发现覆盖本身就是结论的一部分,它说明攻击者或管理员做过什么,必须写进报告,不能只写"未发现相关记录"。
2.2 服务仍在运行意味着什么
这是本篇最需要强调的部分。服务在线时,以下动作会主动销毁或改写证据:
| 你的动作(或时间的流逝) |
后果 |
| 什么都不做,等一天 |
logrotate 覆盖掉最后一份包含入侵时段的 access.log |
| 攻击者发现自己被发现了 |
删除 WebShell、清空 history、truncate -s 0 清日志 |
你执行 bt restart / service nginx restart |
新 worker 启动,日志句柄变化,部分日志被截断重开 |
你执行 rm/mv 网站文件 |
目录项分离(ext4)后 fls 也难定位,覆盖数据概率高 |
| 磁盘写满 |
大量文件写入失败,日志直接丢失,站点报错 |
| 你关机 |
/tmp(若 tmpfs)内容全部消失,utmp 清空,未落盘的 journal 丢失 |
因此服务器现场的处置顺序是硬性的:
1. 抢占式固定(分钟级):内存镜像 + 关键日志定向复制 + 远程备份/只读快照(云主机)
↓
2. 网络层隔离(不是关机):防火墙限流或断网,保留 SSH 通道给取证人员
↓
3. 决定是否停服(能冻结证据,但会中断业务 → 需委托方书面同意)
↓
4. 全盘镜像 → 5. 离线深度分析(此时已无时间压力)
关键判断:先固定后隔离,先隔离后停服,停服需授权。 直接拔电虽然"最安全地冻结了现场",但会销毁内存证据和 tmpfs 内容,对服务器往往是净损失。
2.3 关键路径速查表
按安装方式不同,Web 环境分散在三处。宝塔是国内最主流的,下面三组路径都要查:
| 路径 |
内容 |
取证价值 |
参见 |
/www/wwwroot/<site>/ |
宝塔站点根目录(对 Web 用户可写) |
★★★★★ |
06 |
/www/server/panel/data/ |
面板数据库与配置 |
★★★★★ |
02 / 03 |
/www/server/panel/logs/ |
面板请求与操作日志 |
★★★★★ |
02 |
/www/server/panel/vhost/ |
宝塔生成的站点配置 |
★★★★★ |
05 |
/www/server/nginx/conf/ |
宝塔自编译的 Nginx(非 /etc/nginx) |
★★★★★ |
05 |
/www/wwwlogs/ |
宝塔的网站日志目录(非 /var/log/nginx) |
★★★★★ |
07 |
/www/backup/ |
宝塔自动备份(站点+数据库) |
★★★★ |
02 |
/var/www/ |
源包安装 / 非面板环境的站点根 |
★★★★ |
06 |
/etc/nginx/、/var/log/nginx/ |
发行版安装的 Nginx 配置与日志 |
★★★★★ |
05 / 07 |
/etc/passwd、/etc/shadow |
账户与口令哈希 |
★★★★ |
见《Linux 取证 — 取证工件地图》 |
/etc/cron.d/、/var/spool/cron/crontabs/ |
计划任务(面板也能写) |
★★★★★ |
见《计划任务与持久化痕迹》 |
/var/log/auth.log / secure |
SSH 登录记录 |
★★★★ |
见《SSH 痕迹与密钥取证》 |
/root/.bash_history、/home/*/.bash_history |
面板/SSH 操作留下的命令历史 |
★★★★★ |
见《Shell 痕迹与命令历史》 |
⚠️ 最容易漏的三个目录:
/www/backup/ —— 宝塔每天自动备份网站和数据库。勒索事件中它可能包含被加密前的原始数据,也可能是攻击者已污染的副本。
/www/wwwlogs/ —— 宝塔的日志不在 /var/log/nginx,去那里找会得到"没有访问日志"的错误结论。
/www/server/nginx/conf/ —— 宝塔的 Nginx 是自己编译安装的,配置不在 /etc/nginx。
2.4 站点根目录的"可写"问题
这是服务器场景最核心的攻击面。Web 服务进程(www-data / nginx / apache)必须能写站点目录,否则无法接收上传——这是业务的硬需求,也是攻击者的入口:
任何一处上传/写入成功 → 写 .php 到站点目录(Web 进程对该目录可写且有执行权限)
→ HTTP 访问该文件,代码以 Web 服务账号执行
→ 该账号能读数据库配置(.env、config.php)→ 拿到库口令
→ 改配置把 WebShell 上传到任意站点 / 写 crontab(若有权限)→ 提权
取证含义:站点目录里出现的任何"非业务文件"都要单独解释(WebShell 不会自己写 README)。
权限组合要重点看。755 root:root 尚可,777 www:www 是重大风险信号;站点目录里有其他用户(如数据库账号)可写的子目录,则构成横向移动路径。
PHP 禁用函数列表是被篡改过的关键证据(disable_functions 被清空 = 有人在面板里改过它),见第 05 篇。
2.5 /home 与数据库层
/home 在服务器上的含义和 PC 不同。除运维账户 home(.bash_history 常有面板操作记录、.ssh/authorized_keys 是公钥植入位置)外,很多面板/环境的站点根本身也在这里。/opt/、/usr/local/、/var/lib/tomcat/ 是应用实际部署位置,其中 deploy.sh、.env、*.jar 的 mtime 是判断"部署制品是否被动手脚"的锚点。
数据库层的工件决定案件最终能拿到什么数据。最重要的两个是 general_log(记录所有语句含 SELECT,默认关闭、体积巨大)与 binlog(默认开启、有天数上限、ROW 格式可还原每行改动的旧值/新值)。
拖库行为在 binlog 里几乎必然留下痕迹。 路径见下表(均在 /var/lib/mysql/ 或 /var/log/mysql/ 下,以实际环境为准):
| 路径 |
内容 |
取证价值 |
mysql-bin.0000xx |
binlog,含全部写操作 |
★★★★★ |
mysql.slow_query_log |
慢查询(批量导出数据的间接证据) |
★★★★★ |
general_log / general_log_file |
通用查询日志,含 SELECT |
★★★★★ |
error.log |
错误日志 |
★★★★ |
show processlist 导出 |
只能在线拿到的当前活跃查询 |
★★★★★ |
三、操作步骤
3.1 第 0 步(现场在线时):抢占式固定
这一节只适用于服务器仍在运行的情况。 顺序不可颠倒。
# 1) 记录时间基准与当前状态(先做,因为它几秒后就变)
date -u '+%Y-%m-%dT%H:%M:%SZ' | tee /evidence/collection-utc.txt
uptime; who -a; last -n 30
# 2) 当前网络连接与监听端口 —— 只存在于内存,抢时间价值最高
ss -tulpn | tee /evidence/netstat-live.txt
ss -tapn state established >> /evidence/netstat-live.txt
ps auxwwf | tee /evidence/ps-live.txt
# 3) 内存镜像(时间允许时优先做;LiME 需编译加载模块,AVML 静态可执行)
sudo ./avml /evidence/DigiForensics-mem.raw
sha256sum /evidence/DigiForensics-mem.raw | tee /evidence/mem.sha256
# 4) 关键日志定向复制(只 cp,不 mv、不 truncate)
mkdir -p /evidence/logs
for f in /var/log/nginx/*.log /www/wwwlogs/*.log /var/log/auth.log \
/var/log/secure /www/server/panel/logs/*.log; do
[ -f "$f" ] && cp -p --preserve=timestamps "$f" /evidence/logs/ 2>/dev/null
done
# 5) 面板数据与站点配置(数据库可能正在被写,需尽快复制)
cp -p /www/server/panel/data/default.db /evidence/ 2>/dev/null
cp -rp /www/server/panel/data/db/ /evidence/bt-db/ 2>/dev/null
cp -rp /www/server/panel/vhost/ /evidence/bt-vhost/ 2>/dev/null
cp -p /www/server/panel/data/div.pl /evidence/ 2>/dev/null
⚠️ 不要 mv 日志文件。 移动会导致服务继续写入被移走的 inode(对已打开的 fd 而言),在原目录留下 .1 空壳,而你手上的文件是"活"的、还在被写的,内容不可复现。cp 是唯一正确动作。
3.2 第 1 步:只读接入与身份确认
grep -E '^(NAME|VERSION_ID)=' /mnt/df/etc/os-release
for d in /www/server/panel /opt/1panel /etc/webmin /www/wwwroot /var/www; do
[ -d "/mnt/df$d" ] && echo "存在 $d" || echo "缺失 $d"
done
ls -d /mnt/df/www/server/nginx /mnt/df/etc/nginx /mnt/df/etc/httpd 2>/dev/null
3.3 第 2 步:优先级排序 —— "先看什么"
这是本篇最需要记住的清单。顺序即价值密度,前面的步骤能独立形成结论,后面的用于补全。
| 优先级 |
目标 |
具体动作 |
为什么排这个位置 |
| 1 |
网站目录 |
列 /www/wwwroot 全部站点;找非业务文件、异常 mtime、异常权限 |
唯一直接指向"已被入侵"的物证,且不会被日志轮转冲掉 |
| 2 |
访问日志 |
分析 access.log 的可疑请求(见第 07 篇) |
唯一能回答"什么时候、被怎么打进来的" |
| 3 |
计划任务 / 持久化 |
crontab、/etc/cron.d、systemd 自定义 unit |
攻击者必留,清理成本高 |
| 4 |
账户与 SSH |
passwd、shadow、authorized_keys、auth.log |
回答"用什么身份进来" |
| 5 |
面板 |
面板日志、面板数据库、入口与口令(见[ |
|