服务器集群中挖矿病毒的排查修复

8/30/2024 CPU挖矿病毒BusyBox替代系统命令UnHide查找隐藏进程云沙箱分析病毒

# 1. 整体情况

# 1.1 服务器集群概况

组内共有19台实体服务器在数据中心进行托管,其中大多是GPU服务器,主要用于模型训练及推理使用,统一安装了CentOS系统,通过Slurm将其组成一个集群。本次共有17台服务器中了CPU挖矿病毒,另外2台服务器不在集群里,幸免于难。

设备名称 设备厂商 CPU核心 显卡配置 操作系统
mu01 Inspur 20 无显卡 CentOS 7.9.2009
cpu01 Dell 6 无显卡 CentOS 7.9.2009
cpu02 同泰怡 36 无显卡 CentOS 7.9.2009
cpu03 同泰怡 36 无显卡 CentOS 7.9.2009
cpu04 嘉创 32 无显卡 CentOS 7.9.2010
gpu01 Inspur 20 GeForce RTX 2080 Ti(11019MB)*6 CentOS 7.9.2009
gpu02 Inspur 20 GeForce RTX 2080 Ti(11019MB)*6 CentOS 7.9.2009
gpu03 Inspur 20 GeForce RTX 2080 Ti(11019MB)*6 CentOS 7.9.2009
gpu04 Inspur 12 GeForce GTX TITAN X(12212MB)*4 CentOS 7.9.2009
gpu05 Inspur 20 GeForce RTX 2080 Ti(11019MB)*8 CentOS 7.9.2009
gpu06 Supermicro 20 TITAN RTX(24220MB)*4 CentOS 7.9.2009
gpu07 Supermicro 32 GeForce RTX 3090(24268MB)*4 CentOS 7.9.2009
gpu08 Supermicro 32 GeForce RTX 3090(24268MB)*8 CentOS 7.9.2009
gpu09 Dell 56 GeForce RTX 3090(24268MB)*8 CentOS 7.9.2009
gpu10 Inspur 64 GeForce RTX A800(81920MB)*8 CentOS 7.9.2009
gpu11 Inspur 64 GeForce RTX A800(81920MB)*8 CentOS 7.9.2009
gpu12 Inspur 64 GeForce RTX A800(81920MB)*8 CentOS 7.9.2009
gpu13 ASUS 80 GeForce RTX 4090(24564MB)*8 CentOS 7.9.2009
gpu14 ASUS 80 GeForce RTX 4090(24564MB)*4 CentOS 7.9.2009

# 1.2 CPU挖矿病毒特征

根据本次排查过程中遇到的情况,可以总结出CPU挖矿病毒的以下主要特征:

特征 描述
高CPU占用率 全核心或部分核心被挖矿进程占满,影响系统性能
系统命令篡改 系统命令被篡改替换,导致无法正常执行系统操作
隐藏恶意进程 恶意进程被隐藏,难以通过常规命令检测
异常流量连接 与境外IP建立网络连接,频繁更换IP地址
进程自动重启 存在守护进程或计划任务,停掉之后还会自动重启
中断杀软运行 能够把杀软的守护进程给干掉,使其无法正常运行

# 2. 系统异常

# 2.1 发现过程

# 2.1.1 iptables与Docker异常

启动Docker容器时出现了报错,两种情况都是iptables出现了问题,重装iptables、Docker之后恢复了正常。

[1] 部分服务器启动Docker容器报错,改成宿主机网络后,还能把Docker容器运行起来。

$ docker run -d -p 7777:7777 --name basellm basellm-image:latest       // 启动不起来,报错
$ docker run -d --network host --name basellm basellm-image:latest     // 可以成功启动
1
2

报错信息与iptables有关。

290202a1d7682eb9238a1b4aefea394857a84eab53a6b809fe7c4897ae9156da
docker: Error response from daemon: driver failed programming external connectivity on endpoint basellm (abf4649e6b298b6f33bb8fe7006b7b10d0993c2aa429a86d57094902b24cd0cd):  (iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport 7777 -j DNAT --to-destination 172.17.0.3:7777 ! -i docker0:  (fork/exec /usr/sbin/iptables: no such file or directory)).
1
2

[2] 另外一部分服务器可能是其它成员重启过Docker,我发现时整个Docker都启动不起来了。

$ journalctl -xe
$ journalctl -u docker.service --since "5 minutes ago"
1
2

报错信息也与iptables有关。

8月 28 15:41:41 gpu10 dockerd[25338]: time="2024-08-28T15:41:41.995406002+08:00" level=info msg="Loading containers: start."
8月 28 15:41:42 gpu10 dockerd[25338]: time="2024-08-28T15:41:42.006674303+08:00" level=warning msg="failed to find iptables" error="exec: \"iptables\": executable file not found in $PATH"
8月 28 15:41:42 gpu10 dockerd[25338]: time="2024-08-28T15:41:42.008424542+08:00" level=info msg="stopping event stream following graceful shutdown" error="<nil>" module=libcontainerd namespace=moby
8月 28 15:41:42 gpu10 dockerd[25338]: failed to start daemon: Error initializing network controller: error obtaining controller instance: failed to register "bridge" driver: failed to create NAT chain DOCKER: 
8月 28 15:41:42 gpu10 systemd[1]: docker.service: main process exited, code=exited, status=1/FAILURE
8月 28 15:41:42 gpu10 systemd[1]: Failed to start Docker Application Container Engine.
-- Subject: Unit docker.service has failed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- 
-- Unit docker.service has failed.
-- 
-- The result is failed.
8月 28 15:41:42 gpu10 systemd[1]: Unit docker.service entered failed state.
8月 28 15:41:42 gpu10 systemd[1]: docker.service failed.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

[3] 对 iptables 和 Docker 进行了重装,重装后能够正常使用了,原先的Docker镜像和容器也都还在。

$ yum remove iptables
$ yum --disablerepo="*" --enablerepo="base,updates,extras" --setopt=base.baseurl=https://mirrors.aliyun.com/centos/7/os/x86_64/ --setopt=updates.baseurl=https://mirrors.aliyun.com/centos/7/updates/x86_64/ --setopt=extras.baseurl=https://mirrors.aliyun.com/centos/7/extras/x86_64/ install -y iptables iptables-services

$ curl -fsSL get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh --mirror Aliyun
$ sudo systemctl enable docker
$ sudo systemctl start docker
$ docker version
1
2
3
4
5
6
7
8

# 2.1.2 GPU掉卡及CPU占用异常

[1] 其中有一台服务器使用 nvidia-smi 命令查询时,发现只能查询到3张显卡信息(这台服务器上是有4张显卡的),之前遇到过热掉卡的情况,重启后即可恢复正常,但这次重启命令却不生效了。

$ nvidia-smi               // 只查询到3张卡的信息
$ reboot                   // 命令不生效,无法重启
1
2

[2] 之后去机房物理重启服务器,显卡信息查询恢复正常,但是机器非常热,于是又去查询资源占用,发现所有CPU核心都被吃满了。

$ htop
1

挖矿病毒导致服务器GPU占满

# 2.2 中毒现象

# 2.2.1 服务器中毒表现

发现服务器不太对劲之后,我们在后续的排查过程中又发现了一些情况,总结如下:

  • CPU占用异常升高:部分服务器的CPU是全部跑满,另外还有一些服务器的CPU是占用了50%。
  • 找不到高占用的进程:使用htop与top命令找不到任何不正常的高占用进程,被隐藏起来了。
  • iptables出现问题:iptables相关文件损坏,无法将其启动,Docker也受之影响无法正常使用了。
  • 系统命令被替换:halt、poweroff、reboot和shutdown等命令均被替换,无法正常使用。
  • 日志被删除、历史命令被清空:/var/log/auth.log等日志文件被删除,history历史命令被清空。

# 2.2.2 进一步确认中毒

发现服务器有了这么多异常之后,就去网上查询相关问题,在相关博客中得知可能是中了挖矿病毒,然后继续通过以下尝试进行了确认。

有一些病毒会把自身编译成二进制,然后替换系统软件,非常具有迷惑性。系统有方法可以快速检查软件是否被替换,原理就是把系统文件的大小、修改日期、权限、哈希等信息与软件仓库中记录的信息比较,找出不同的文件。

[1] 执行如下命令,发现有问题的服务器输出以下内容,文件确实是被篡改了;而没有问题的服务器,没有输出内容,都是正常的。

$ rpm -Vf /bin/ps
S.5......    /usr/bin/top
S.5......    /usr/bin/uptime
S.5......    /usr/bin/w

$ rpm -Vf /usr/bin/top
S.5......    /usr/bin/top
S.5......    /usr/bin/uptime
S.5......    /usr/bin/w
1
2
3
4
5
6
7
8
9

输入解读:rpm 是 Red Hat Package Manager 的命令行工具,-V选项用于验证包中文件的状态,-f选项指定要验证的文件。

输出解读:如果一切均校验正常将不会产生任何输出,如果有不一致的地方,就会显示出来,输出格式是8位长字符串,每个字符都用以表示文件与rpm数据库中一种属性的比较结果 ,如果是. (点) 则表示测试通过。

标志 介绍
S 文件大小是否改变
M 文件的类型或文件的权限(rwx)是否被改变
5 文件MD5校验是否改变(可以看成文件内容是否改变)
D 设备中,从代码是否改变
L 文件路径是否改变
U 文件的属主(所有者)是否改变
G 文件的属组是否改变
T 文件的修改时间是否改变

[2] 然后又使用stat查看命令的最近更改时间,发现的确是最近被改了。

$ stat /bin/ps
$ stat /usr/bin/top 

文件:"/usr/bin/top"
大小:1311768           块:2568       IO 块:4096   普通文件
设备:804h/2052d        Inode:3774425606  硬链接:1
权限:(0755/-rwxr-xr-x)  Uid:(    0/    root)   Gid:(    0/    root)
最近访问:2024-08-30 11:16:35.048417550 +0800
最近更改:2020-10-01 01:21:37.000000000 +0800
最近改动:2024-08-27 07:14:27.082438019 +0800
创建时间:-
1
2
3
4
5
6
7
8
9
10
11

[3] 之后又使用了如下命令导出了所有rpm软件包的校验检查结果,查看哪些命令被替换了。

$ rpm -Va > rpm.log
1

# 3. 内部排查

排查:我们首先查阅了网上的一些资料,经过一番努力之后,找到了病毒进程,但我们始终找不到它的驻留方式,然后很多系统命令也被弄坏了,即便干掉病毒也很难恢复,觉得搞不定了orz,因此打算备份重装了[世上无难事,只要肯放弃],服务器上几百TB的数据可要了老命了,光采购备份数据的磁盘就要好几万。(PS:其中的部分排查是有效的,后续有转机)

# 3.1 使用BusyBox替代系统命令

# 3.1.1 BusyBox工具简介

Busybox在单一的可执行文件中提供了精简的Unix工具集,可运行于多款POSIX环境的操作系统,例如Linux(包括Android)、Hurd、FreeBSD等等。由于BusyBox可执行文件的文件比较小,使得它非常适合使用于嵌入式系统。

# 3.1.2 安装BusyBox工具

由于服务器上的某些系统命令被病毒篡改了,直接使用系统命令可能根本找不到病毒的相关信息,因此我们需要先安装一个BusyBox工具,替代系统命令用于问题排查。

$ wget https://busybox.net/downloads/binaries/1.31.0-defconfig-multiarch-musl/busybox-x86_64
$ cp busybox-x86_64 /usr/local/bin/busybox
$ chmod +x /usr/local/bin/busybox
$ busybox 
1
2
3
4

busybox工具的使用是非常简单的,在原生的Linux命令的前面加上busybox即可,需要注意的是它的输出格式可能与系统命令不同,一些复杂的组合命令可能需要进行调整才能使用。

# 3.2 发现异常流量的境外IP地址

# 3.2.1 分析服务器流量

使用 netstat 命令分析服务器流量,但由于命令可能已经遭到篡改,因此这里通过 busybox 来使用。

$ busybox netstat
1

这里发现了个“138.68.113.5”的外部陌生IP地址。

netstat分析服务器流量

# 3.2.2 分析异常流量的IP地址

然后使用 IP地址属地查询工具 (opens new window) 查询得知这个IP的属地是德国,大概率是矿池的IP。

挖矿病毒的IP归属地

通过拦截IP的方式是没有用的,因为它肯定是有个巨大的IP池,会一直更换IP地址。

# 3.3 从隐藏进程里找到病毒进程

# 3.3.1 UnHide工具简介

UnHide 用各种技术手段和算法,对系统进行深入扫描和分析,以寻找和发现被隐藏的进程、TCP/UDP端口以及其他隐藏技术。它可以帮助取证人员或安全专家发现系统中的潜在威胁,并采取相应的措施进行应对和防御。

UnHide工作机制:

  • ROOTKIT 和 LKM:ROOTKIT是一种恶意软件,常用于隐藏恶意活动和进程。它通过修改操作系统的核心组件和内核模块(LKM)来实现对系统的隐匿。UnHide 使用一些技术手段来检测这些隐藏的进程和模块,例如扫描系统文件、比对内存映像等。
  • TCP/UDP端口隐藏:某些恶意软件可能会在系统上开启隐藏的TCP或UDP端口,使得这些端口无法通过常规手段检测到。UnHide 使用技术手段来扫描系统中的所有端口,并尝试发现被隐藏的端口。
  • 其他隐藏技术:除了上述两种常见的隐藏技术,UnHide 还可以探测其他形式的隐藏,比如隐藏的文件、目录、注册表项等。它通过检查系统的文件系统、注册表以及其他关键信息来识别这些隐藏的元素。

# 3.3.2 安装UnHide工具

UnHide工具可以直接使用yum来安装。

$ yum install unhide
1

# 3.3.3 查找系统隐藏进程

使用 unhide proc 命令可以用来查找隐藏进程。

$ unhide proc
1

使用该命令查询果然到了大量隐藏进程,这些进程就是挖矿病毒搞的鬼。

挖矿病毒的隐藏进程

以18000的进程为例,想要根据进程找到它的文件所在位置,发现它都是运行起来就删掉了。

$ ls -l /proc/18000/exe
lrwxrwxrwx 1 root root 0 830 23:53 /proc/18000/exe -> /cec40678 (deleted)
1
2

这些进程之间都是存在关联的,一个进程被干掉了之后,这些进程就都没了,CPU的资源占用也恢复了正常。

$ kill 18000
$ unhide proc
$ htop
1
2
3

干掉挖矿病毒进程后的CPU占用

注:虽然把挖矿病毒的进程干掉了,但这还是远远不够的,没有将病毒文件找到并清除,它还可以通过开机启动项、计划任务等方式进行重启(查找过crontab定时任务,但并没有将其找到),实践中我们发现它也的确是会死灰复燃。

# 3.4 使用GScan进行安全扫描

# 3.4.1 GScan工具简介

GScan工具本旨在为安全应急响应人员对Linux主机排查时提供便利,实现主机侧Checklist的自动全面化检测,根据检测结果自动数据聚合,进行黑客攻击路径溯源。

运行环境与兼容性:

  • 系统:CentOS (6、7) + Python (2.x、3.x)。
  • 兼容性:目前官方只针对CentOS进行了兼容性测试,其它系统检测结果未知。(注:我在Debian11系统也能成功跑出结果)
  • 权限:root权限启动。
  • 执行时间:默认安全扫描大概执行时间为4~6分钟,完全扫描在1~2小时之间,程序执行时间的长度由检测文件的多少决定,可能会需要较长的时间,请耐心等待。

# 3.4.2 安装GScan工具

直接从Github拉取源码即可,不需要安装依赖环境,开箱即用,里面的GScan.py是启动程序。

$ git clone https://github.com/grayddq/GScan.git
1

# 3.4.3 自动扫描安全风险

直接执行GScan.py脚本即可运行,它将会自动扫描安全风险。

$ cd GScan 
$ python3 GScan.py -h         // 查看帮助
$ python3 GScan.py            // 开始扫描
1
2
3

GScan工具的使用帮助

服务器文件很多的话,这个扫描过程会很慢,我在生产环境的服务器扫描了一天也没啥进度,放弃使用该工具进行扫描了。

注:我在个人服务器也用该工具尝试扫描了一下(与本次病毒查杀无关,只是试试这个工具多久能扫描完,看看扫描结果是怎样的),服务器有130GB文件,耗时2h才扫描完,在控制台里打印了类似这样的风险信息。

GScan扫描结果

# 3.5 使用卡巴斯基尝试查杀病毒

我们又尝试使用卡巴斯基去查杀病毒,它能够把病毒的进程停掉一段时间,但还是没有办法彻底清除病毒文件,之后病毒还是会自动启动,并且把卡巴斯基的守护进程停掉,还是会死灰复燃。

# 4. 外部协助

转机:后来找了外部的网络安全专业人士帮忙分析和排查,在得到高人指点之后,终于找到了这个病毒的源程序,将其彻底清除掉了。

# 4.1 查找病毒并取样

# 4.1.1 扫描隐藏进程

通过之前使用过的 unhide proc 命令扫描隐藏进程。

$ unhide proc
1

UnHide查找隐藏进程

发现存在大量隐藏进程,但都是/6abd8f7c

# 4.1.2 找到病毒主程序

通过PID号(选择其中之一就行了,都是同一个程序)查询服务状态,以此确定相关目录路径。

$ systemctl status 2033
1

通过PID查找病毒进程的位置

/usr/lib/systemd/system/5a6a2504.service 文件为隐藏文件,直接使用ls命令是看不到的,但可以通过cat命令查看内容。

$ cat /usr/lib/systemd/system/5a6a2504.service
1

查看病毒进程的内容

这里找到病毒的主程序了,这个/usr/bin/5a6a2504e2731c11病毒主程序也同样为隐藏文件。

# 4.1.3 对病毒进行取样

对病毒进行取样分析,复制一份保存为/tmp/bak。取样之后,将其下载下来,然后删掉服务器上的这个病毒样本。

$ cp /usr/bin/5a6a2504e2731c11 /tmp/bak
$ rm -f /tmp/bak
1
2

# 4.2 微步云沙箱分析病毒

# 4.2.1 上传病毒样本

使用Chrome浏览器打开微步云沙箱在线工具,这个需要注册登录一下。

微步云沙箱工具

文件上传之后,选择一个分析环境,这里尽量跟中毒服务器的保持一致。

选择微步云沙箱的分析环境

# 4.2.2 病毒分析结果

微步云沙箱可以给出病毒的分析结果,确定该病毒的类型为Derusbin家族使用的恶意程序。

微步云沙箱的分析结果

可以看到市面上绝大多数免费的杀软都检测不到该病毒。

该病毒的杀毒引擎的检出率

可以查看到病毒的执行流程和释放过程,这个可以用来分析病毒对我们系统做了什么。

病毒的释放过程

可以查看到病毒的网络行为,可以看到它的IP通向了矿池。

查看病毒的网络行为

最后,可以看到病毒释放了哪些文件,方便我们之后对病毒进行彻底清除。

病毒释放的文件

# 4.3 清除病毒并安全加固

# 4.3.1 彻底清除病毒

Step1:将病毒主程序及释放出来的文件都删掉

  • 删除/usr/lib/systemd/system/5a6a2504.service,其中5a6a2504为随机命名。
  • 删除/usr/bin/5a6a2504e2731c11,其中5a6a2504e2731c11为随机命名。
  • 保险起见,根据微步云沙箱的详细分析报告,将病毒释放的那些文件全部清除。
$ rm -f /usr/lib/systemd/system/5a6a2504.service
$ rm -f /usr/bin/5a6a2504e2731c11
1
2

Step2:根据PID将病毒进程kill掉,使用htop查看CPU占用并持续一段时间对其监控。

$ kill -9 2033
$ htop
1
2

Step3:根据病毒的释放过程,分析病毒删了、篡改了哪些系统文件,评估一下是单独安装这些系统文件还是整体系统重装。

# 4.3.2 安全防护加固

[1] 排查时发现其中一个节点上有八千多次失败的登录尝试,可能是因为弱口令被暴力破解了密码,安全加固措施如下:

  • 修改所有服务器的连接密码,将之前的弱密码全部换成由字母、数字、符号共同组成的无规则长密码。
  • 更换为非22端口,通过设置prohibit-password,禁止root账号使用密码登录,只让其使用密钥进行登录。
  • 检查 /root/.ssh/authorized_keys有没有留下后门密钥,防止黑客通过密钥继续保持服务器的访问权限。

[2] 定期对服务器进行备份,还好这次只是挖矿病毒,要是勒索病毒那可就麻烦了。在服务器上部署主机防护软件,例如“安恒EDR”。

# 5. 参考资料

[1] Linux系统CPU使用率和负载高排查方法 from 阿里云 (opens new window)

[2] 怎么快速对比,取证机器有哪些系统命令文件被篡改 from CSDN (opens new window)

[3] Linux入侵排查 from Emergency-Response-Notes (opens new window)

[4] linux挖矿入侵排查 from 尘世中一个迷途小书童 (opens new window)

[5] ubuntu服务器内网遭受了ssh暴破攻击,服务器上被部署了挖矿病毒 from 尘世中一个迷途小书童 (opens new window)

[6] 瞎点广告,被黑客注入了挖矿病毒怎么办? from Bilibili (opens new window)

[7] CPU被挖矿了,却找不到哪个进程 from 51CTO (opens new window)

[8] linux下隐藏进程 from CSDN (opens new window)

[9] 服务器被攻击植入挖矿病毒,CPU占用高问题排查处理 from CSDN (opens new window)

[10] 记一次挖矿病毒的应急响应 from CSDN (opens new window)

[11] 服务器CPU占用50%,top/htop/ps却看不到异常进程?本文带你彻底杀毒 from CSDN (opens new window)

[12] 服务器遭遇挖矿行为-相应进程被隐藏 from CSDN (opens new window)

[13] 挖矿病毒处置(Linux篇) ——从入门到放弃 from 西安交通大学 (opens new window)

[14] 近期部分服务器感染“挖矿”病毒的清理指南 from 北京大学 (opens new window)

Last Updated: 10/21/2024, 10:22:10 AM