资讯详情

资讯详情

CPU飙高?挖矿病毒清理全流程:排查、清除与系统加固

中招的那天我记得很清楚业务群里开始有人抱怨“页面加载好慢”我随手登上服务器一看负载直接飙到80多8个核心全部拉满。top里排在第一位的是一个叫不出名字的进程CPU占用990%。那一刻我就明白了——这是挖矿病毒找上门了。这类事情现在太常见了。攻击者利用各种未授权访问或系统漏洞往机器里塞一个矿工程序占用你的CPU去挖数字货币然后通过矿池把收益抽走。机器越卡你的业务越受影响账单上的电费和带宽费用也在悄悄涨。我这篇文章就围绕“挖矿病毒清理”这件事把整个排查、定位、清除、加固的过程完整写一遍适合所有自己管服务器、管虚拟机、或者公司里负责运维的同学参考无论你是第一次遇到还是已经踩过坑应该都能从中找到有用的东西。1. 症状先别慌从CPU飙到确认挖矿进程的判断清单很多人第一反应是先把进程kill掉赶紧让CPU降下来。这个做法我可以很直接地告诉你基本没用。挖矿病毒几乎都会带一个守护进程或者自愈机制你杀死一个过几十秒它又起来了CPU照旧拉满。所以在动手之前先花几分钟把现场看清楚反而能省下一整天的折腾。1.1 哪些异常现象需要警惕挖矿病毒不是无迹可寻的它的痕迹主要集中在几个维度CPU占用异常飙升正常情况下业务高峰期CPU有波动但挖矿病毒是持续性的尤其是深夜低峰期CPU使用率依然在80%以上这就非常可疑。风扇狂转、机器卡顿物理机如果风扇突然全速转且没有任何重业务任务在跑多半是中毒。带宽占用异常矿机与矿池之间需要持续通信网卡流量会出现大量外发数据包。如果你看到明明没有多少用户访问出站流量却跑满得长个心眼。文件系统出现异常/tmp、/var/tmp、/dev/shm这类目录里出现奇怪的脚本或二进制文件后缀可能是.sh、.bin也可能是完全没有后缀的一堆随机字母。我自己遇到过最典型的场景是一台专门跑数据备份的机器白天根本没什么人在用但是运维平台告警说CPU连续15分钟超过90%。上去一看8个核全是同一个进程在用命令行里还带着明明几个月前就已经停掉的旧脚本路径。这种情况基本可以当场断定挖矿病毒找了个缝钻进来然后把旧脚本当幌子藏在了进程里。1.2 三条命令快速圈定可疑进程确认是否中挖矿病毒不需要装什么重型工具Linux自带的几个命令就够用。第一遍排查我习惯按下面的顺序来# 查看CPU占用最高的进程-c 可以显示完整命令行 top -c # 按CPU使用率排序只看前20行 ps aux --sort-%cpu | head -20 # 查看当前所有的网络连接包括进程信息 ss -tnptop -c的用处在于它能把完整命令行列出来很多挖矿进程会起一个看起来像系统服务的名字比如java -version、php-fpm之类的伪装。但如果你看到命令里明显有一个wget下载链接或者有一段base64 -d解出来的脚本在跑那基本就是中招了。ss -tnp则是看连接挖矿进程一定会和矿池地址建立TCP连接连接列表里那些一个进程连着多个外部IP、持续不断的状态就是重点怀疑对象。第一次排查不需要赶时间把可疑进程的PID记下来再对照时间看看这些进程是什么时候出现的。我一般还会顺手跑一句uptime看平均负载再对比一下业务低峰期的正常负载心里就有底了。整个确认过程控制在十分钟以内就够了别因为着急把事情越搞越乱。2. 顺藤摸瓜把藏着的病毒文件和矿池连接全部翻出来确认有挖矿进程之后下一步不是急着清理而是“顺藤摸瓜”。什么意思就是通过进程信息把病毒文件、启动脚本、矿池地址这三大要素全部找出来。这三个要素缺一不可漏了文件光杀进程没用漏了矿池地址病毒会换一个池子继续漏了启动项重启之后它照样复活。2.1 通过 /proc 目录把进程的老底翻出来Linux的/proc目录是非常好用的调试入口它会把每个进程的运行状态和资源占用地清清楚楚地映射在文件系统里。我查挖矿病毒最依赖的就是下面这套组合# 查看进程启动时的完整命令行把空字节替换成空格 cat /proc/PID/cmdline | tr \0 # 找到可执行文件在磁盘上的真实路径 ls -l /proc/PID/exe # 查看进程当前的工作目录 ls -l /proc/PID/cwd # 列出进程打开的所有文件 ls -l /proc/PID/fd这条路的逻辑很简单进程的cmdline里如果有下载链接多半是样本脚本exe指向的路径就是真正的挖矿二进制文件cwd能看到病毒是在哪个目录里被拉起来的fd里的信息更丰富有可能连带出日志文件、配置文件、甚至已经删除但仍被持有的文件。这里有一个非常实用的细节很多挖矿进程为了隐藏自身会把自己从磁盘上删掉但进程还在内存里跑。这时候你执行ls -l /proc/PID/exe路径后面会带一行奇怪的提示比如/tmp/xxx.sh (deleted)。不要慌这恰恰说明病毒文件虽然被删但样本还能从进程的内存里还原出来信息量反而更大。可以顺便把/proc/PID/environ读出来看看有没有异常的环境变量有时候攻击者会在里面藏矿池的配置参数。2.2 反向确认它连的到底是哪个矿池现在我们手里有了一个“不招供”的进程接着就得看看它在跟谁通信。偷家挖矿总是要出货的矿池地址是它绕不开的痕迹。执行ss -tnp之后找到可疑PID对应的外部IP和端口记录下来源地址和目标地址。挖矿流量有几个典型特征连接是长连接状态一般表现为ESTAB过一会儿再看仍然连着的那些外部地址十有八九是矿池节点。有两点值得注意矿池地址可能会伪装成正常的HTTPS流量走443端口但连接源明确来自一个本机异常进程这就不能用“正常的HTTPS请求”来解释了。有的挖矿木马会先解析一个随机域名再连接动态IP。这类域名通常看起来完全没有规律比如一串乱码加一个陌生顶级域。拿到这些IP和域名之后先别急着删东西。把它们加到防火墙的封禁列表里等于先切断了病毒的“出货通道”。这一步的意义很大哪怕你暂时没时间彻底清理文件先断掉矿池通信CPU占用也会明显降下来因为矿机挖出来的东西交不出去很多挖矿程序会进入重试等待状态。我习惯立刻执行两条命令把口子封住# 封死矿池IP的出站连接 iptables -A OUTPUT -d 矿池IP -j DROP # 如果是域名先解析出IP再同样封禁整理信息的时候顺手把相关文件的时间戳、大小、权限也记下来。这些看起来琐碎的东西后面判断是否存在多个变种文件时会派上大用场。很多挖矿病毒不止一个样本母体是shell脚本子体才是真正的矿机还有可能带了清除竞争木马的辅助脚本多记录一份就不容易被表象带偏。3. 病毒复活的关键定时任务、服务与各种自启后门挖矿病毒之所以难缠是因为它总是把“持久化”这件事做到极致。所谓持久化就是确保机器重启、进程被杀、系统更新之后它依然能回来。绝大多数被清理后依然反复发作的案例都是因为持久化机制没有彻底清除而不是病毒本身有多高级。所以这一步我们得把系统里所有可能被利用的自动启动通道全部翻一遍。3.1 定时任务是最常见的复活通道挖矿木马最常用的持久化手段就是往crontab里塞一条任务内容一般是每隔几分钟从某个地址下载脚本并执行。为什么用cron因为cron是系统自带功能不会报毒跑起来无声无息而且几分钟一次能确保任何被清理的动作都会被自动“修复”。排查定时任务只看自己用户的crontab是不够的要按用户和系统两个维度都查一遍# 查看当前用户的定时任务 crontab -l # 查看系统级的定时任务目录 ls -la /etc/cron.d/ /etc/cron.hourly/ /etc/cron.daily/ 2/dev/null # 查看所有用户自己的crontab需要root权限 for user in $(cut -f1 -d: /etc/passwd); do echo $user ; crontab -u $user -l 2/dev/null; done我在实际排查中见过几种典型的隐藏手法有的把脚本写在/etc/cron.d/下文件名伪装成nginx有的在/var/spool/cron/目录里为root用户写一条任务却没给文件所有者设任何提示还有的会故意在脚本开头sleep 100让排查人员等不到它发作。这些手法都不可怕关键是要通读一遍所有定时任务的内容而不是只看有没有可疑名字。看到任务里包含wget、curl、base64 -d、chmod x这些组合哪怕它外面包着一层正常业务脚本的壳也要当成重点对象处理。3.2 systemd服务与开机脚本里藏着的守护进程定时任务只是入口之一。现代的挖矿病毒还会创建systemd服务因为服务由系统自动拉起杀进程之后systemd会自动重启它这一类比cron更难对付。排查服务可以这样# 列出所有enabled状态的服务重点看最近新增的 systemctl list-unit-files --stateenabled # 查看服务文件的内容 cat /etc/systemd/system/服务名.service # 也可以查看服务的安装来源 systemctl cat 服务名典型的挖矿服务有几个特征服务描述字段是空或者是乱写的ExecStart指向的是/tmp或家目录下的一个脚本服务的Restart设置成always保证进程一死就被拉起。找到之后需要systemctl stop、systemctl disable再删掉对应的.service文件缺一步都不行否则下次开机还是会被启用。除了systemd还要看一眼传统的启动脚本。/etc/rc.local、/etc/profile.d/、~/.bashrc、~/.zshrc都可能是寄生场所。有个很阴险的套路是把一段下载逻辑塞进~/.bashrc里平时根本看不出异常但只要用户登录一次shell就会触发下载。这种用“用户行为”作为触发器的持久化排查起来比服务隐蔽得多。3.3 更隐蔽的驻留命令替换与动态度加载如果病毒想在更深的层面藏身它就不仅仅满足于“开机自启”了而是要让管理员根本看不到它。最常见的做法有两个替换系统命令或者通过预加载机制过滤信息。替换系统命令意味着把ps、top、ss、netstat、lsof这些管理员常用的排查命令替换成病毒的木马版本真业务进程会被这些假命令过滤掉。怎么发现执行一下ls -l /bin/ps看文件修改时间是不是近期对比一下/bin/ps和同目录下其他命令的时间戳是否一致也可以安装一个干净的busybox用busybox ps来对比输出。另外还可以借助stat看文件大小木马版往往比正版小很多。第二种是动态度预加载它通过/etc/ld.so.preload文件让所有新启动的程序自动加载一个恶意动态库这个动态库可以拦截常见的读取系统进程和目录列表的系统调用。也就是说你在输出里看不到病毒进程但它确确实实在跑。排查手法是查看/etc/ld.so.preload是否存在正常情况下这个文件应该是空文件或不存在一旦里面有内容基本就是中招了。这种情况下建议谨慎使用系统自带的命令去读更好的做法是用一个干净的系统盘或者挂载只读方式去检查。面对这些深层驻留不是说一定要一次挖到最底层但至少先了解它们的存在。很多运维同学清理挖矿病毒只是“清了表面症状”过几天又复发其实复发的原因就在于这些更深层的机制没被发现。4. 清理顺序决定成败从断网到删除的完整操作流程前面铺垫那么多现在进入真正动手的阶段。清理挖矿病毒最忌讳的就是“上线就杀”没有准备动作、没有顺序意识会把本来可以一次解决的问题搞成反复发作。我整理了一套操作顺序照这个流程走成功率高很多。4.1 清理前的三步准备记录、断连、备份证据准备阶段花不了几分钟但能让后续所有操作都有退路。第一记录现场。把当前进程列表、网络连接、crontab内容、服务列表都导出来存到一台干净机器上。别小看这一步公司里如果要求溯源这些记录就是最直接的第一手材料。# 保存现场 ps aux /tmp/ps_snapshot.txt ss -tnp /tmp/ss_snapshot.txt crontab -l /tmp/crontab_snapshot.txt 2/dev/null systemctl list-unit-files --stateenabled /tmp/service_snapshot.txt第二断开矿池连接。这一步在排查过程中已经可以做这里再换成更保险的方式如果机器部署在云环境且有安全组直接先把出站流量规则收紧只放行业务必须的端口如果只是想快速处置用iptables把已知矿池IP全部丢进DROP规则里。断掉矿池通信后就算清理动作慢半拍病毒也无法从中获利了。第三备份可疑文件。不要急着rm先把可疑二进制和脚本打包留档比如tar czvf /root/malware_samples.tar.gz /tmp/某个可疑目录 /root/.config/某个可疑文件这份样本是后续做病毒特征分析、确认变种范围、甚至同步给安全同事的重要依据。很多情况下你以为只感染了一个文件打包的时候才发现同一个时间戳下有四五个关联文件这些都是“同批产物”一起打包利于整体判断。4.2 正式清理的完整命令参考清理的黄金顺序是先断进程树再删文件最后清驻留配置。如果顺序反了进程会在文件被删除前再次把文件拉回来等于白做。下面的命令请根据你自己排查到的实际情况替换对应值# 1. 按匹配模式结束进程树这里以某个随机命名的挖矿进程为例 # 先在ps输出里确认匹配模式再执行 pkill -9 -f 某挖矿进程的独有特征字符串 # 2. 删除磁盘上的病毒样本 rm -f /tmp/某个病毒目录/病毒脚本 rm -f /usr/bin/某个被替换的命令 # 如果确认被替换需要从干净备份恢复 # 3. 清理crontab里被写入的恶意任务 crontab -e # 手动删除恶意行保存退出 # 4. 清理systemd服务 systemctl stop 恶意服务名 systemctl disable 恶意服务名 rm -f /etc/systemd/system/恶意服务名.service systemctl daemon-reload # 5. 清理预加载库和启动脚本 cat /etc/ld.so.preload # 确认内容后置空 echo -n /etc/ld.so.preload这里要特别说明“进程树”这个操作。挖矿病毒通常会启动多个子进程你直接kill PID可能只杀掉一个子进程父进程马上又会拉一个全新的出来。用pkill -f按特征字符串匹配则可以把所有相关进程一锅端但前提是这个字符串足够独特比如病毒文件的路径、矿池的域名片段。如果拿不准可以先执行一次带匹配的ps aux | grep 特征确认能匹配到哪些进程再动手。4.3 重启前的复核确认没有漏网之鱼清理完一轮别急着松口气。我习惯在重启之前做一次系统性的复核确保没有遗漏。核心是检查三个层面进程层面有没有新的可疑进程冒出来、网络层面有没有新的异常连接、配置文件层面有没有被改回来。常用的复核命令组合在这里# 再次查看是否有挖矿特征进程 ps aux --sort-%cpu | head -20 # 检查是否还有陌生外联 ss -tnp # 检查常见驻留目录是否又被写入文件 ls -la /tmp /var/tmp /dev/shm ls -la /etc/cron.d/ /var/spool/cron/ # 全盘查找近7天内被修改的可执行文件 find / -xdev -type f -mtime -7 -perm /111 -size 1M 2/dev/null | head -50如果你做完这些检查发现CPU已经降回正常水平网络连接里再也找不到矿池地址/tmp下面也没有新生成的可疑脚本那么基本可以判定清理工作完成了一大半。不过还有一条很多人会漏掉登录日志和SSH配置。看一下/var/log/secure或者/var/log/auth.log确认有没有异常来源的登录成功记录再看~/.ssh/authorized_keys有没有不属于自己的公钥被塞进去。攻击者拿到主机的第一步往往就是种SSH后门所以清理挖矿病毒时顺手清掉后门公钥能有效防止对方卷土重来。5. 清干净只是开始系统加固与后续哨兵监控把眼前的病毒清理完只算解决了燃眉之急。很多机器因为同样的漏洞被多次入侵防火墙也没有针对矿池IP做长期封禁所以过一两周又中一次。真正的收尾工作是加固和监控让下一次入侵的成本变高、暴露的时间变短。5.1 立刻要做的六项安全加固按照优先级排序下面这几项是清理完成后必须马上做的修改所有账号的登录密码和SSH密钥尤其是root账号。挖矿病毒入侵后攻击者往往会拿走系统里的各类凭据你不改对方随时可以再次登录。清点并清理SSH信任关系。检查每台机器的authorized_keys删掉所有不认识的公钥匙条目。SSH服务加固禁用root直接登录限制允许登录的用户名单有条件的开启秘钥登录并禁掉密码登录。收紧对外暴露的服务端口。用防火墙只放行业务需要的端口数据库、消息队列、容器管理平台这类高危服务绝对不要裸奔在公网上。更新系统与软件补丁。清理过程中确认了入侵途径后对应的漏洞补丁必须第一时间打上否则清理得再干净也是白搭。统一修改被复用过的应用密码。很多内网服务用的是同一套密码一处失守等于处处失守这个步骤不能偷懒。5.2 布置长期监控在下次中招前提前发现加固做了但你不能保证100%不被攻破所以还需要让系统具备“早发现”的能力。我的做法不需要复杂组件一台机器上布置几组简单监控就够了。第一个是CPU与进程的周期性巡检。写一个简单的脚本定时采集CPU占用最高的前5个进程如果发现异常立即记录并通知。脚本本身不复杂核心就是把之前手动执行的top命令做成自动化的#!/bin/bash # 采集CPU占用异常时追加到告警日志 top -b -n 1 | head -20 /var/log/cpu_audit.log awk $1 80 { print strftime(%F %T), $0 } /var/log/cpu_audit.log第二个是文件系统敏感目录的变更监控。监控/etc/cron*、/var/spool/cron、/tmp、/dev/shm这些目录的文件新增和修改情况。可以用inotifywait这类工具如果觉得配置麻烦至少每周手动执行一次find按照修改时间排序检查有没有可疑的新文件。第三个是登录日志的异常检测。定期扫描日志里的登录失败、新增用户、sudo使用记录。实际上线之后我发现大部分入侵都发生在凌晨两三点到五六点之间一台正常业务机器在那个时段根本不该有人登录所以把时段条件加进去之后误报会少很多。5.3 根据我个人经验给同样遇到过挖矿病毒的同学几个建议整个流程走下来我最想叮嘱的有三件事。第一不要迷信“一键查杀工具”系统里命令工具都不可信了一键工具也很难做到真正彻底手动按流程走一遍永远最稳妥。第二清理过程中别急着重启机器很多信息只有在不重启的情况下才能查得到真到了需要重启的那一步前提是你已经把该收集的证据都收集完了。第三清完一次之后24小时后一定要再复查一遍确认CPU没有再拉满、连接里没有新矿池地址才能宣布彻底结束。最后分享一个小技巧。很多挖矿病毒都会修改系统时间或者用kill等信号假装自己退出实际还留在内存里。处理这类情况时可以用ps -eo pid,ppid,cmd,etime多看一眼进程的启动时间和存活时长凡是启动时间异常早、重启后还能“活着”的进程都要多留一个心眼。这类小细节往往就是决定一次清理成功还是失败的分水岭。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →