这个问题很少是凭空冒出来的。服务器变慢了,主机商发来关于外发流量的邮件,或者邮箱里出现了一条你并未做过的登录通知。接下来就是不愉快的部分:不清楚该看什么、按什么顺序看,而第一反应——全删了重装——几乎总是操之过急。
下面是一套大约二十分钟的检查顺序,多数情况下能给出明确答案。它从最便宜的往最昂贵的走:先看立刻就能看到的,再看必须与某个基准比对的。
第一步:谁登录过
从登录记录开始。如果有别人进来了,几乎可以肯定是通过 SSH 进来的,而痕迹还在。
last -20
lastb | head -20
who
last 显示最近的成功登录,lastb 显示失败的,who 显示此刻谁在连接。重要的不是数量而是形态。来自那些再也不会回来的地址的成千上万次失败尝试,就是普通的背景噪声;它对每一个公网地址不停地跑,什么也说明不了。
该担心的是另外一些事:
- 来自没有你的人的地址的成功登录;
- 用你从未创建过的用户名登录;
- 针对这台机器上确实存在的用户名的失败尝试——这意味着有人已经知道了你的用户列表,而不是在跑字典;
- 此刻打开的、并非你打开的会话。
另外单独检查是否出现了陌生的密钥。文件 ~/.ssh/authorized_keys 是最常见的留驻方式:密码随便改多少次,密钥依然在。
cat ~/.ssh/authorized_keys
sudo cat /root/.ssh/authorized_keys
那里的每一行都是某个人的访问权限。如果你说不出是谁的,就当成是别人的。
第二步:系统里有什么变化
入侵几乎总会在磁盘上留下痕迹:被替换的二进制文件、配置里多出的一行、Web 服务器目录下的新文件。用肉眼检查是没指望的——需要一个比对基准。
在 Debian 和 Ubuntu 上这个基准本来就有:每个软件包都知道自己文件的校验和。
sudo apt install debsums
sudo debsums -c
这条命令会列出与发行版所安装内容不一致的文件。其中一部分结果是合理的——/etc 里的配置文件本来就是用来改的。但在一台你从未手动动过的服务器上,/usr/bin、/usr/sbin 或 /bin 里被改动的可执行文件,完全是另一回事。
第二个来源是本不该有新东西的地方出现的新文件。web shell 通常待在上传目录里,看起来像一个人畜无害的 .php:
find /var/www -type f -name '*.php' -mtime -14 -ls
十四天只是起点;请用你确定没有发布过任何内容的那段时间。
第三步:有什么在往外走
被攻陷的服务器很少是为了它本身而被攻破的。它会被利用:发垃圾邮件、挖矿、伸向别的网络、存放别人的文件。所有这些都会产生此前没有的外发连接。
ss -tulpn
ss -tp state established
第一条命令显示什么在监听,第二条显示此刻连着什么。请读进程那一列。会引起疑问的是:某个陌生进程在 0.0.0.0 上监听;到你的应用毫无关系的地址的高端口的外发连接;以及最要紧的,从 /tmp 或 /dev/shm 启动的进程——没有任何合法的东西从这些目录里运行。
顺便也看一下负载。挖矿程序会自我暴露:在一个毫无人气的站点上却让处理器一直忙着。
如果这些迹象出现了
第一冲动是赶紧清理:删掉陌生密钥、杀掉进程、删除文件。别这么做——与此同时被毁掉的,正是日后能说明他们是怎么进来的那个东西。而如果这一点始终不清楚,他们会回来,也许就在明天。
既保住数据又保住全貌的顺序:
- 如果服务商提供,就先做磁盘快照。这是唯一一个事后无法重来的步骤。
- 把机器从网络上断开,或者关闭除你的 IP 之外的一切——但不要关机。关机会丢失进程列表和打开的连接,而那是一半的证据。
- 把日志复制到机器之外:
/var/log/auth.log、Web 服务器的日志、上面三条命令的输出。 - 到这时才开始弄清他们是怎么进来的。
如果访问权限是以 root 身份取得的,那么彻底重装是正确的收尾。任何清理都无法保证没有东西被留下。但不理解原因就重装是没有意义的:你会把同一个漏洞搬到新系统上。
让这个问题不再突然降临
上面这一切都是一次性的手动检查,它回答的是「此刻正在发生什么」。麻烦在于这个问题往往问得太晚:等到服务商已经来信或者站点已经倒下。
其中每一项检查都有对应的独立工具可以持续盯着:失败登录——fail2ban,文件变化——AIDE,软件包完整性——debsums,开放端口——定期的 ss 快照。一个个装上并不难;难的是养成每天登录去读六份不同输出的习惯,正因如此实际上没人会去读。
把它们汇总到一个面板的全部意义正在于此:同样的数据,但在一个页面上并且带着历史,好让「昨天不是这样」自己映入眼帘,而不必专门去查。下面的演示页面展示了拼在一起时它是什么样子。