2024年1月19日下午,我正忙别的事,监控突然弹出一条告警:一台很久没动的CentOS测试服务器,CPU使用率连续15分钟超过300%。开始我还以为是同事的压测脚本跑错了地方,SSH上去之后,top 输出让我立刻清醒了——一个叫 kdevtmpfsi 的进程占了好几个核,CPU时间累计到几十个小时。这台机器最近没有任何发布记录,也没有我们手工配置的定时任务。我心里基本确定:这是中了挖矿木马。
接下来四个小时,我一直在和这个进程背后的一整套持久化机制斗智斗勇。为什么这里要专门写一篇记录?因为这类问题到现在依然很常见,尤其是 Redis、Docker 这类服务端口暴露过的机器。如果你也遇到服务器 CPU 突然飙高、对外连接异常,或者明明把进程杀了又自动复活,这份排障路径可以直接参考。
1. 现场现象与初步判断:别一看到高 CPU 就动手 kill
很多人遇到服务器 CPU 飙满,第一反应就是 top 看到高占用进程,然后 kill -9。这个操作不是完全没用,但在应急响应里属于最不该先做的事。我这次也差点犯这个错,后来发现先留现场信息,远比先杀进程重要。
1.1 我能理解“想赶紧杀掉”的心情,但先记录现场
kill 本身很容易,难的是搞清楚它为什么会出现在那里。进程一旦被 kill,很多关键信息就散了:父进程是谁、打开过什么文件、连着哪个 IP、启动参数是什么。这些恰恰是判断入侵路径的重要线索。
我上机后先执行了这么几条命令,把输出保存到本地:
bash复制date; hostname; uptime
top -bn1 | head -30
ps -eo pid,ppid,%cpu,%mem,user,etime,cmd --sort=-%cpu | head -20
当时看到的信息大概是这样的:
load average: 12.30, 8.71, 5.22- PID 27431,用户 root,CPU 占用 746%
- 进程名
kdevtmpfsi - 进程路径指向
/tmp/kdevtmpfsi
一个普通测试机不可能有业务进程叫这个名字,更不可能长期占满 CPU。etime 显示这个进程已经运行了一段时间,说明入侵可能发生在前一天,只是这台机器没人关注,所以一直没被发现。
1.2 判断异常进程不能只看名字
现在很多挖矿木马会把进程伪装成 dockerd、containerd、kworker 甚至 systemd,只靠名字认不出问题。我通常从下面几个维度综合判断:
| 判断维度 | 这台机器上的现象 | 正常进程应该有的样子 |
|---|---|---|
| CPU 占用 | 单个进程持续 700%+,且没有对应业务 | 和实际负载匹配,不会长期吃满 |
| 进程路径 | /tmp/kdevtmpfsi,运行后文件已删除 |
一般是 /usr/bin、/usr/sbin 或项目目录 |
| 父进程 | PPID 1,但 systemd 里找不到对应 unit | 有明确的 systemd 服务或业务父进程 |
| 网络连接 | 高频连接境外 IP 的 4444 端口 | 只连已知业务端口、更新源 |
| 启动时间 | 和系统异常时间吻合 | 和业务启动、系统启动时间吻合 |
/tmp 目录本来就不应该放可执行文件,如果发现一个进程从 /tmp 或 /var/tmp 启动,基本可以直接判定为可疑。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 顺着进程反查:kdevtmpfsi 背后还有一条下载链
记录完现场之后,我没有
