个人站最容易出问题的不是代码,而是「你不在电脑前的那几个小时」。SSH 暴力破解、被当成代理跳板、挖矿脚本跑满 CPU、网站被挂马——这些事的共性是:发生时不吵不闹,等你发现时已经跑了几天。这篇文章讲的是被动防御之外的那一层:怎么把一次入侵在日志里留下的痕迹找出来,以及在没有专业安全团队的前提下,把日常监控做到「够用」。
一、先建立「正常」的基线,否则一切异常都无从判断
排查入侵的第一句话永远是「这个进程正常吗」。没有基线,你只能靠搜索引擎猜。基线不复杂,四样东西就够:进程清单(ps aux 的稳定快照)、监听端口(ss -lntup)、自启项(systemd 单元与 crontab)、账号列表(/etc/passwd 的普通用户与 uid 0 用户)。
做法是把这四样存成文件,每周或每次发版后重新生成一份,用 diff 比对:
SNAP=/root/baseline
mkdir -p $SNAP
ps -eo user,pid,ppid,etime,cmd --sort=pid > $SNAP/ps.txt
ss -lntup > $SNAP/listen.txt
systemctl list-units --type=service --state=running --no-pager > $SNAP/units.txt
crontab -l > $SNAP/cron_root.txt 2>/dev/null
diff $SNAP/ps.txt.latest $SNAP/ps.txt | head -30注意用 --sort=pid 固定顺序,否则 diff 全是噪声。这一条看着琐碎,但它是后面所有判断的地基。
二、进程可疑的五个特征,按可信度排序
先看进程名。挖矿程序现在很聪明,进程名往往伪装成 kdevtmpfsi、kworkerds、sysupdate 这类像内核线程的名字。判别方法很简单:真正的内核线程在 ps 里带方括号([kworker/0:1]),且 /proc/PID/exe 指向空;伪装的挖矿进程是普通用户态进程,ls -l /proc/PID/exe 会显示已被删除的可执行文件路径——这是最硬的证据之一。
第二个特征是 CPU 占用与业务不匹配。一台只跑 PHP-FPM 与 MySQL 的机器,如果 top 里出现一个 400% 占用的无名进程,而且 nice 值是 19、PRI 很低,基本可以判定。第三个是网络:ss -tnp 里出现到陌生 IP 的 3333、5555、7777、14444 这类矿池常用端口的出站连接。第四个是路径:可执行文件放在 /tmp、/dev/shm、/var/tmp、/root/.config 下的都是高危。第五个是父子关系:ppid 是 1 但 etime 很短、且不来自 systemd 单元的进程,值得逐个看。
按这五条排序很重要——先看 /proc/PID/exe,因为它是不可伪装的;名字与端口都能被改,路径可以被 symlink 欺瞒,exe 指向的 inode 却骗不了。
三、把登录日志读懂:不是看到失败就报警
公网上的 SSH 端口每天收几千次失败登录是常态。真正需要关注的是三类:成功登录、来自陌生国家的成功登录、以及针对 root 的成功登录。lastb 与 last 分别看失败与成功,格式里要重点看 IP 与时间。用一条聚合指令看谁在密集尝试:
grep 'Failed password' /var/log/auth.log \
| awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -20输出的第一列是尝试次数,第二列是来源 IP。排在前面的未必是威胁——可能是你某个忘改密钥的合法客户端在重试。关键是要能分辨「高频失败」与「失败之后成功」:只要同一 IP 既有大量失败又有一条成功,就必须当作入侵事件处理,改密码、换密钥、查 ~/.ssh/authorized_keys 是否多了公钥。
另一个常被忽略的入口是面板与数据库。宝塔、phpMyAdmin、MySQL 的 3306 如果直接暴露在公网,日志格式不同、位置不同,往往没人看。/var/log/mysql/error.log 里连续的 Access denied for user 就是被扫描的证据。整改方向只有一个:把这些端口从公网撤掉,只允许本机或跳板机访问。
四、文件与时间的交叉验证:找到「被改过」的网页
挂马最常见的形态是在 index.php 或模板文件里插入一行 eval 或一个外链脚本。find 按修改时间筛选是最快的入口:
find /www/wwwroot -type f -newermt '-7 days' -name '*.php' \
| grep -v -E 'cache|runtime|session' | head -50如果近七天你自己没动过这些文件,它们就该被逐个看。第二步看内容特征:eval($_POST、base64_decode(、gzinflate(、assert($_REQUEST、preg_replace.*\/e 这几组串在正常业务代码里几乎不会出现。第三步看权限与所有者:新增的 644 文件属于 www 用户、而其他文件属于 root,就是上传漏洞留下的痕迹。
需要提醒的是,mtime 可以被 touch -r 伪造。更可靠的信号是 ctime(inode 变更时间),普通用户无法篡改,stat 命令可以看到。AIDE 这类完整性工具的价值就在于此——它记的是文件内容哈希,不看时间戳。
五、网络层痕迹:连接表比进程表活得更久
入侵者常常在做事前先删掉脚本、清掉进程,但连接与路由的痕迹不容易一次抹干净。三个地方值得看:ss -tnp state established 的当前连接、/proc/net/tcp 里的十六进制记录(即使 ss 被替换,这个内核接口一般是干净的)、以及 ip route 与 iptables -t nat -L -n 里有没有你没写过的转发规则。挖矿木马经常顺手开一个 SOCKS 代理,落地在 nat 表的一条 REDIRECT 上。
还有一个容易被忽略的点是 DNS。cat /etc/resolv.conf 如果指向了一个陌生 IP,说明有程序改过它——这是 DNS 劫持类木马的常见动作,目的是把某些域名的解析指向自己的服务器。同样要看 /etc/hosts 是不是多了奇怪条目,以及 lsattr /etc/resolv.conf 是否被设了 +i 不可变属性(有些木马会这么做,防止你改回去)。
更进一步的检查是看防火墙计数:如果某条 ACCEPT 规则的包计数在持续增长,而你不知道谁在用,就顺着来源 IP 去看访问日志,通常能定位到具体的异常请求路径。这类排查不需要专业工具,iptables -vnL 的 pkts 列配合 conntrack -L 就够了。
六、日志审计的第一原则:先保住日志,再分析
很多事故复盘做到一半就断了,原因是被入侵者清掉了日志:/var/log/auth.log 被截断、last 记录被清空、bash history 被删。所以真正做监控的第一步不是分析,而是把日志送到「从这台机器上删不掉」的地方。最轻量的方案是每天的 cron 把关键日志按日期压缩后 rsync 到另一台机器或对象存储:
rsync -az /var/log/ --include='auth.log*' --include='secure*' \
--include='nginx/*' --exclude='*' backup@10.0.0.9:/logs/$(hostname)/日志被清空这件事本身也是一个强信号。如果你的日志轮转没有配置 rotate 30 这种较长的保留期,很容易出现「昨天的日志已经被轮转掉」的假象。判断方法:ls -l /var/log/auth.log* 看文件大小是否突然变小,以及 last -f /var/log/wtmp 与 ls -l /var/log/wtmp 的 mtime 是否匹配。
七、把「发现」做成每天五分钟的例行
一个人的站不可能天天做安全审计,所以只能把检查压缩成几个「看一眼就知道有没有事」的指标。我的做法是每天早上一封自建邮件,正文四行:新增的 uid 0 账号数、监听端口与昨天相比的增减、近 24 小时 SSH 成功登录的次数与非白名单 IP、/tmp 与 /dev/shm 下可执行文件的数量。
awk -F: '$3==0{print $1}' /etc/passwd
ss -lntu | awk 'NR>1{print $5}' | sort | uniq -c
last -i -s yesterday | grep -v -f /root/whitelist_ips.txt | wc -l
find /tmp /dev/shm -type f -perm -u+x | wc -l这四行的价值在于「变化」而非「绝对值」。只要昨天是 3、今天变成 9,你就知道该去看什么了。不需要理解所有字段,只需要建立「数字变了就查」的条件反射。
八、真正被入侵之后的处理次序
确认被入侵后,最容易做错的是「边查边跑」。正确的次序是:先把对外服务摘掉(改 DNS 指到静态维护页,或在防火墙层只放行你的 IP),再取证据(内存快照、进程列表、网络连接、关键日志打包),再评估范围(只这一台,还是横向到了数据库与内网),最后才是清理与重装。经验上,只要拿到了 root 权限,重装是最省时间的方案,清理干净比重装难得多——后门可能藏在 systemd 单元、内核模块、或者你以为已经删掉的用户家目录里。
重装之后必须回补两点:一是把当时导致入侵的入口补上(弱密码、暴露的面板、过期的插件),二是把上面那四行日报真正跑起来。安全事故往往不是第一次被攻破造成的损失最大,而是同一个洞被攻破第二次。