# 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 // 可以成功启动
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)).
2
[2] 另外一部分服务器可能是其它成员重启过Docker,我发现时整个Docker都启动不起来了。
$ journalctl -xe
$ journalctl -u docker.service --since "5 minutes ago"
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.
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
2
3
4
5
6
7
8
# 2.1.2 GPU掉卡及CPU占用异常
[1] 其中有一台服务器使用 nvidia-smi 命令查询时,发现只能查询到3张显卡信息(这台服务器上是有4张显卡的),之前遇到过热掉卡的情况,重启后即可恢复正常,但这次重启命令却不生效了。
$ nvidia-smi // 只查询到3张卡的信息
$ reboot // 命令不生效,无法重启
2
[2] 之后去机房物理重启服务器,显卡信息查询恢复正常,但是机器非常热,于是又去查询资源占用,发现所有CPU核心都被吃满了。
$ htop
# 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
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
创建时间:-
2
3
4
5
6
7
8
9
10
11
[3] 之后又使用了如下命令导出了所有rpm软件包的校验检查结果,查看哪些命令被替换了。
$ rpm -Va > rpm.log
# 3. 内部排查
排查:我们首先查阅了网上的一些资料,经过一番努力之后,找到了病毒进程,但我们始终找不到它的驻留方式,然后很多系统命令也被弄坏了,即便干掉病毒也很难恢复,觉得搞不定了orz,因此打算备份重装了[世上无难事,只要肯放弃],服务器上几百TB的数据可要了老命了,光采购备份数据的磁盘就要好几万。(PS:其中的部分排查是有效的,后续有转机)
# 3.1 使用BusyBox替代系统命令
# 3.1.1 BusyBox工具简介
Busybox在单一的可执行文件中提供了精简的Unix工具集,可运行于多款POSIX环境的操作系统,例如Linux(包括Android)、Hurd、FreeBSD等等。由于BusyBox可执行文件的文件比较小,使得它非常适合使用于嵌入式系统。
- 官网地址:https://www.busybox.net (opens new window)
- 项目地址:https://github.com/mirror/busybox (opens new window)
# 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
2
3
4
busybox工具的使用是非常简单的,在原生的Linux命令的前面加上busybox即可,需要注意的是它的输出格式可能与系统命令不同,一些复杂的组合命令可能需要进行调整才能使用。
# 3.2 发现异常流量的境外IP地址
# 3.2.1 分析服务器流量
使用 netstat 命令分析服务器流量,但由于命令可能已经遭到篡改,因此这里通过 busybox 来使用。
$ busybox netstat
这里发现了个“138.68.113.5”的外部陌生IP地址。
# 3.2.2 分析异常流量的IP地址
然后使用 IP地址属地查询工具 (opens new window) 查询得知这个IP的属地是德国,大概率是矿池的IP。
通过拦截IP的方式是没有用的,因为它肯定是有个巨大的IP池,会一直更换IP地址。
# 3.3 从隐藏进程里找到病毒进程
# 3.3.1 UnHide工具简介
UnHide 用各种技术手段和算法,对系统进行深入扫描和分析,以寻找和发现被隐藏的进程、TCP/UDP端口以及其他隐藏技术。它可以帮助取证人员或安全专家发现系统中的潜在威胁,并采取相应的措施进行应对和防御。
- 官网地址:https://www.unhide-forensics.info (opens new window)
- 项目地址:https://github.com/YJesus/Unhide (opens new window)
UnHide工作机制:
- ROOTKIT 和 LKM:ROOTKIT是一种恶意软件,常用于隐藏恶意活动和进程。它通过修改操作系统的核心组件和内核模块(LKM)来实现对系统的隐匿。UnHide 使用一些技术手段来检测这些隐藏的进程和模块,例如扫描系统文件、比对内存映像等。
- TCP/UDP端口隐藏:某些恶意软件可能会在系统上开启隐藏的TCP或UDP端口,使得这些端口无法通过常规手段检测到。UnHide 使用技术手段来扫描系统中的所有端口,并尝试发现被隐藏的端口。
- 其他隐藏技术:除了上述两种常见的隐藏技术,UnHide 还可以探测其他形式的隐藏,比如隐藏的文件、目录、注册表项等。它通过检查系统的文件系统、注册表以及其他关键信息来识别这些隐藏的元素。
# 3.3.2 安装UnHide工具
UnHide工具可以直接使用yum来安装。
$ yum install unhide
# 3.3.3 查找系统隐藏进程
使用 unhide proc 命令可以用来查找隐藏进程。
$ unhide proc
使用该命令查询果然到了大量隐藏进程,这些进程就是挖矿病毒搞的鬼。
以18000的进程为例,想要根据进程找到它的文件所在位置,发现它都是运行起来就删掉了。
$ ls -l /proc/18000/exe
lrwxrwxrwx 1 root root 0 8月 30 23:53 /proc/18000/exe -> /cec40678 (deleted)
2
这些进程之间都是存在关联的,一个进程被干掉了之后,这些进程就都没了,CPU的资源占用也恢复了正常。
$ kill 18000
$ unhide proc
$ htop
2
3
注:虽然把挖矿病毒的进程干掉了,但这还是远远不够的,没有将病毒文件找到并清除,它还可以通过开机启动项、计划任务等方式进行重启(查找过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
# 3.4.3 自动扫描安全风险
直接执行GScan.py脚本即可运行,它将会自动扫描安全风险。
$ cd GScan
$ python3 GScan.py -h // 查看帮助
$ python3 GScan.py // 开始扫描
2
3
服务器文件很多的话,这个扫描过程会很慢,我在生产环境的服务器扫描了一天也没啥进度,放弃使用该工具进行扫描了。
注:我在个人服务器也用该工具尝试扫描了一下(与本次病毒查杀无关,只是试试这个工具多久能扫描完,看看扫描结果是怎样的),服务器有130GB文件,耗时2h才扫描完,在控制台里打印了类似这样的风险信息。
# 3.5 使用卡巴斯基尝试查杀病毒
我们又尝试使用卡巴斯基去查杀病毒,它能够把病毒的进程停掉一段时间,但还是没有办法彻底清除病毒文件,之后病毒还是会自动启动,并且把卡巴斯基的守护进程停掉,还是会死灰复燃。
# 4. 外部协助
转机:后来找了外部的网络安全专业人士帮忙分析和排查,在得到高人指点之后,终于找到了这个病毒的源程序,将其彻底清除掉了。
# 4.1 查找病毒并取样
# 4.1.1 扫描隐藏进程
通过之前使用过的 unhide proc 命令扫描隐藏进程。
$ unhide proc
发现存在大量隐藏进程,但都是/6abd8f7c
。
# 4.1.2 找到病毒主程序
通过PID号(选择其中之一就行了,都是同一个程序)查询服务状态,以此确定相关目录路径。
$ systemctl status 2033
/usr/lib/systemd/system/5a6a2504.service
文件为隐藏文件,直接使用ls命令是看不到的,但可以通过cat命令查看内容。
$ cat /usr/lib/systemd/system/5a6a2504.service
这里找到病毒的主程序了,这个/usr/bin/5a6a2504e2731c11
病毒主程序也同样为隐藏文件。
# 4.1.3 对病毒进行取样
对病毒进行取样分析,复制一份保存为/tmp/bak
。取样之后,将其下载下来,然后删掉服务器上的这个病毒样本。
$ cp /usr/bin/5a6a2504e2731c11 /tmp/bak
$ rm -f /tmp/bak
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
2
Step2:根据PID将病毒进程kill掉,使用htop查看CPU占用并持续一段时间对其监控。
$ kill -9 2033
$ htop
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)