malware · cryptomining · rootkit · linux · kernel · monero · privilege-escalation · cve-2026-31431 · container-escape
Rootpacket:一个藏身内核的 Linux 挖矿木马工具包
Kinryū Labs 分析了 Rootpacket,一个 Linux 挖矿木马工具包:它携带一个内核 rootkit 来伪造 CPU 与内存占用,通过 CVE-2026-31431(一个 AF_ALG 页缓存缺陷,还能从容器逃逸到主机)提权到 root,伪装成 Intel 驱动,并关闭竞争对手矿工赖以进入的那些暴露服务。
作者 Davis Zheng·
TLP:CLEAR。已批准公开发布。这是纯静态分析:未执行任何样本,所有结论均来自字符串提取、反汇编与源码审阅。攻击者的门罗币钱包、矿池与基础设施作为防御指标予以公开。
摘要
- ~45%top 显示的占用率,而它实际跑在接近 100%
- 3种持久化机制
- 7.8CVSS,CVE-2026-31431(AF_ALG 页缓存 LPE)
- 主机从一个无特权容器拿到 root
Rootpacket 是一个面向 Linux 的多组件挖矿木马工具包。它打包了一个用于隐身的内核级 rootkit、一个针对 Linux AF_ALG 加密接口中 CVE-2026-31431 的提权漏洞利用、一个被改名为 xrandom 的 UPX 加壳 XMRig 6.26.0 门罗币矿工,以及一个竞争对手清除脚本。代码大量使用土耳其语(变量名、注释、状态字符串),指向一名讲土耳其语的操作者。
该工具包以两种模式之一运行。在 root 模式下,它加载一个伪装成 intel_uncore_freq_aux 的可加载内核模块(LKM)rootkit,通过 DKMS 安装以便在内核升级后依然存活,注册一个 systemd 服务,并把机器上的对手清理干净。当拿不到 root 时,它回退到一种用户态模式,通过 crontab 持久化,并以守护进程方式运行矿工。矿工通过 stratum+ssl 连接到 pool.supportxmr.com:443,用 RandomX 挖门罗币。
值得细看的组件是 rootkit。当矿工把处理器顶在接近 100% 时,rootkit 改写 /proc/stat,让 top 和 htop 报告一个平静的 40 到 50 percent,并用 jiffies 让这个数字上下波动,使负载看起来真实,而不是钉死在一个常数上。它对 /proc/meminfo 做同样的事,还会过滤目录列表以隐藏自己的进程和文件。
关键判断
- 目标是挖矿(高置信度)。工具包携带 XMRig 6.26.0、一个硬编码的门罗币钱包,以及一份
pool.supportxmr.com矿池配置,并关闭了 XMRig 的开发者捐赠,使所有收益都归操作者。 - 提权利用的是 CVE-2026-31431(“Copy Fail”),Linux AF_ALG
algif_aead路径中一处确定性的页缓存写入(CVSS 7.8,2026 年 4 月披露)。由于页缓存是全主机共享的,同一处写入会从容器逃逸出去、拿到主机的 root,因此一个被感染的容器就等于一台被攻陷的主机(高置信度)。 - 操作者的水平远高于典型的「丢下去就挖」团伙(高置信度)。带 ftrace 钩子的定制 LKM rootkit、会为新内核自动重建的 DKMS 持久化、一个可用的 CVE-2026-31431 页缓存利用,以及分层的 systemd/DKMS/cron 持久化,是大多数挖矿木马从未达到的工程水平。
- 操作者很可能讲土耳其语(中等置信度)。土耳其语的变量名、注释以及诸如
ROOT ele gecirildi!的状态信息贯穿整个工具包。 - Rootpacket 的设计是独占一台主机并把它守住。它的
killservice.sh移除竞争对手矿工,然后关闭挖矿木马用于初始访问的那些对外暴露的服务,包括 2375/2376 上的 Docker API——正是我们在 RedTail 报告 中记录过的那个向量。这些团伙都在争夺同一批配置错误的机器。
工具包架构
Rootpacket 是一个模块化的投放器。各个部件:
setup.sh 入口点。检查权限级别,选择部署模式。
getroot 提权。利用 CVE-2026-31431(AF_ALG)实现本地 root。
xrandom UPX 加壳的 XMRig 6.26.0,已改名以躲避基于名称的检测。
kernel/
stealth.c LKM rootkit,通过 DKMS 编译,伪装成 Intel 驱动。
install.sh DKMS 持久化引擎。
killservice.sh 竞争对手清除与「加固」。
rootpacket.tar.gz 整个工具包的内层副本,打包以供再分发。
Root 模式。 若尚非 root,setup.sh 会运行 getroot,把 xrandom 复制到 /opt/kernel-kd/,创建一个 systemd 服务,运行 kernel/install.sh 通过 DKMS 编译并加载 rootkit,运行 killservice.sh 清除竞争对手,然后以持久化服务方式启动矿工。
用户态回退。 当 root 触不可及时,setup.sh 把 xrandom 复制到 ~/.xrandom/,写入一个带 PID 锁的启动器,安装一个在重启时及每分钟触发的 crontab 条目,并用 setsid 启动矿工,使其在父 shell 退出后依然存活。
| 特性 | Root 模式 | 用户态模式 |
|---|---|---|
| 矿工位置 | /opt/kernel-kd/xrandom | ~/.xrandom/xrandom |
| 持久化 | systemd(kernel-kd.service) | crontab(@reboot + */1 * * * *) |
| Rootkit | 有(通过 DKMS 的 LKM) | 无 |
| 竞争对手清除 | 有(killservice.sh) | 无 |
| 运行身份 | root(systemd) | 当前用户(setsid 守护进程) |
getroot:CVE-2026-31431,借页缓存破坏拿到 root
getroot 是一个静态链接、未 strip 的 ELF64 x86-64 二进制,由 getroot.c 构建。它利用 CVE-2026-31431(“Copy Fail”),Linux 内核 AF_ALG algif_aead 接口中的一个逻辑缺陷,于 2026 年 4 月 29 日披露(CVSS 7.8)。该漏洞给出一个确定的、攻击者可控的 4 字节写入到内核页缓存,而 getroot 用它在内存中打补丁一个 SUID 二进制,然后以 root 身份走出来。
| 属性 | 值 |
|---|---|
| 类型 | ELF 64-bit LSB executable,x86-64,静态链接,未 strip |
| CVE | CVE-2026-31431 “Copy Fail”(CVSS 7.8,AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| 子系统 | AF_ALG algif_aead,AEAD 模板 authencesn(hmac(sha256),cbc(aes)) |
| 受影响 | Linux 4.14 到 6.19.11(缺陷于 2017 年随提交 72548b093ee3 引入);已在 6.18.22、6.19.12、7.0+ 修复 |
| 目标 | /usr/bin/su——其内存中的 .text 在页缓存里被打补丁 |
| 可靠性 | 确定性,无竞态条件 |
| 用法 / 兜底 | ./getroot <cmd> [args...];若利用未命中,它仍会以当前权限运行该命令 |
机制。 2017 年 AEAD 代码中的一处就地优化,让被 splice 的页缓存页同时留在源 scatterlist 和目标 scatterlist 中。当 authencesn 模板在攻击者选定的偏移 assoclen + cryptlen 处写入它那 4 字节的 ESN 临时值时,该写入会落在一个用户可读文件的页缓存页内。随后 HMAC 校验失败、recvmsg() 返回 EBADMSG,但内核从不回滚这次写入。getroot 解析 /usr/bin/su 的 ELF 头以计算其入口点的文件偏移,然后循环执行 splice → sendmsg(在 AAD 中携带要写入的 4 字节)→ recvmsg,每 4 字节的 shellcode 一次,在页缓存里给 /usr/bin/su 打补丁。接着它 execve /usr/bin/su:内核加载那个已被破坏的页,shellcode 以 SUID-root 运行,getroot 在运行操作者的命令之前确认 getuid() == 0(并打印土耳其语 [+] ROOT ele gecirildi!,意为「已拿到 root」)。磁盘上的文件从未被触碰,因此文件完整性监控什么也看不到。
逃逸到主机。 Linux 页缓存是全主机共享的;容器并没有自己的页缓存。一个无特权容器内的进程,若 splice 主机的 /usr/bin/su,破坏的是主机那份缓存副本,于是 execve 产出的是主机上的 root,而不仅是容器内的。因此一个被感染的容器就等于一台被攻陷的主机,而 setup.sh 接下来还会把内核 rootkit 加载进主机。停止并删除容器是不够的;主机必须重建。
我们在一台隔离的虚拟机(Kali,内核 6.6.15)上运行过一次 getroot。它执行了完整的 AF_ALG 序列,但在该构建上未拿到 root,回退为以非特权方式运行命令——这与一个针对特定内核布局的利用相吻合。我们没有运行矿工。
xrandom:矿工
xrandom 是开源门罗币矿工 XMRig 6.26.0 的一个改名、UPX 加壳副本。
| 属性 | 值 |
|---|---|
| 真实身份 | XMRig 6.26.0 |
| 加壳 | UPX 4.2.4(加壳 2.8 MB,解包 10.1 MB) |
| 算法 | RandomX(rx/0) |
| 矿池 | 通过 stratum+ssl 的 pool.supportxmr.com:443 |
| 钱包 | 46NVDFL6v5STw5Qw4j77PoBSHRTYnHZGZ8WRoGvHmpaMX7ZyhNUP2u24TLV9pNgncz1bZF2Vm8KkaNTzU7SXqrnFUx5zgHQ |
| 捐赠等级 | 0(已禁用 XMRig 开发者捐赠) |
通过 443 端口 + TLS 挖矿,让流量乍看之下能混入普通的 HTTPS,不过 stratum 握手对任何细看的人来说有着不同的 TLS 指纹。
stealth.c:内核 rootkit
这是整个工具包里最成熟的部分。它是一个 LKM rootkit,使用 ftrace 函数钩子来拦截内核函数、抹除恶意软件的痕迹,并自始至终伪装成一个 Intel 硬件驱动。
| 属性 | 值 |
|---|---|
| 模块名 | intel_uncore_freq_aux |
| 伪造元数据 | MODULE_AUTHOR("Intel Corporation")、MODULE_DESCRIPTION("Intel Uncore Frequency Control Driver")、MODULE_VERSION("1.2.0") |
| 钩子方式 | 通过 kallsyms_lookup_name 的 ftrace(在 5.7 及以后的内核上通过一个 kprobe 解析) |
| 控制 | 位于 /sys/kernel/intel_uncore_freq/ 的 sysfs(enabled、cpu_lo、cpu_hi、mem_lo、mem_hi、hide_tag) |
它钩了什么,以及为什么:
- CPU 掩盖。 它钩
show_stat来改写/proc/stat,在可配置的上下界之间(默认 40 到 50 percent)伪造利用率,并用 jiffies 让数字波动,使其像真实负载一样移动,而不是平躺不动。 - 内存掩盖。 它钩
meminfo_proc_show来改写/proc/meminfo,伪造MemFree、MemAvailable、Buffers、Cached、Active和Inactive。 - 进程隐藏。 它钩
iterate_dir来过滤/proc列表,隐藏名字匹配一组硬编码集合的 PID:stealth、masscan、sshruns、ransomx、cpumask、xrandom、cpm_、kcpm、mask_helper、ftrhook、kintel_aux。操作者可在运行时通过/sys/kernel/intel_uncore_freq/hide_tag添加更多名字。 - 文件隐藏。 它隐藏匹配
stealth、cpumask、kintel_aux、intel_uncore_freq_aux以及 sysfs 目录本身的路径。 - 自我隐藏。 加载时它用
list_del_init把自己从/proc/modules和/sys/module/中移除,删除自己的 sysfs kobject,并用try_module_get增加自身引用计数,使rmmod无法卸载它。
那份隐藏清单本身也是一个线索:除了矿工,它还隐藏了 masscan、sshruns 和 ransomx,所以操作者很可能在运行一个扫描器,并且手里可能不止一个矿工。
实际效果是:一名盯着 top 的管理员,看到的是一台繁忙但正常的机器,找不到流氓进程,也看不到那个正在撒谎的内核模块。破绽是物理的、带外的:机器发烫、风扇转起来、功耗攀升,而这些都不是 rootkit 能伪造的。
持久化:三种机制,按模式区分
Rootpacket 的持久化取决于它落入哪种模式。在 root 模式下,它叠加两种互相加强的机制;在用户态模式下,它回退到第三种。
| # | 机制 | 模式 | 细节 |
|---|---|---|---|
| 1 | systemd 服务 | root | kernel-kd.service,Type=simple,Restart=always,RestartSec=3 |
| 2 | DKMS 模块 | root | 把 rootkit 安装到 /lib/modules/$(uname -r)/extra/ 下;可在内核升级后存活 |
| 3 | crontab | user | @reboot 加每分钟(* * * * *),带 PID 锁与 setsid |
DKMS 条目是最顽固的那个:它通过内核自己的模块构建系统安装 rootkit,因此一次例行的内核升级会重建并重新武装它,而不是移除它。
killservice.sh:清场并封死主机
脚本在其横幅里自称「cryptojacker hardening」(挖矿木马加固),而从操作者的视角看,这个描述很准确。它分三个阶段运行。
阶段 1:关闭暴露的服务。 它针对监听在 0.0.0.0 上、常见的挖矿木马入口,逐一停止、禁用并屏蔽(mask),对其二进制设置 chmod 000,并添加 iptables DROP 规则:
| 服务 | 端口 |
|---|---|
| Redis | 6379 |
| Docker | 2375/2376 |
| PostgreSQL | 5432 |
| MongoDB | 27017 |
| Elasticsearch | 9200/9300 |
| Memcached | 11211 |
| Hadoop YARN | 8088 |
| Jenkins | 8080 |
| Confluence | 8090 |
Docker 这一行是连向我们 RedTail 报告 的纽带:Rootpacket 关上的,正是 RedTail 走进来的那扇 2375/2376 门。先落地的操作者会挖掉这台主机,然后把下一个团伙锁在门外,用对手本会使用的技术来加固这台机器。
阶段 2:移除竞争对手矿工。 它杀进程、删文件、清理 cron 任务,并清除与已知挖矿家族关联的 SSH 密钥,这些家族包括 XMRig、Kinsing(kdevtmpfsi)、TeamTNT(tntrecht、mdrfckr)、sustes、watchdogs 和 minerd,以及 masscan、pnscan、zgrab 等扫描器。
阶段 3:移除用户态 rootkit。 它从 /etc/ld.so.preload 中剥除已知的恶意 LD_PRELOAD 条目(libprocesshider.so、libjdk.so、libpamx.so、一个伪造的 libselinux.so.3,以及 xhide)并删除这些库,清掉可能干扰自己的竞争对手用户态 rootkit。
归因
工具包里土耳其语的变量名、注释与状态字符串(例如 ROOT ele gecirildi!,意为「已拿到 root」)以中等置信度指向一名讲土耳其语的操作者。我们发现了一个位于 linuxutil5.pages[.]dev 的分发或暂存 URL,托管在 Cloudflare Pages 上,这与「把载荷暂存在免费、声誉良好的基础设施上以混入其中」的套路相符。内层的 rootpacket.tar.gz 是整个工具包的自包含副本,给了操作者一个随时可推送到下一台主机的现成包。
失陷指标
网络
| 指标 | 说明 |
|---|---|
pool.supportxmr.com / pool.supportxmr.com:443 | 主门罗币矿池,stratum+ssl |
linuxutil5.pages[.]dev | 分发 / 暂存(Cloudflare Pages) |
api.xmrig.com、randomx.xmrig.com:443 | XMRig API 与基准测试端点 |
donate.v2.xmrig.com、donate.ssl.xmrig.com | XMRig 开发者捐赠矿池(存在,但捐赠已禁用) |
到 443 端口的 stratum+ssl:// | 外连的 TLS 挖矿流量 |
门罗币钱包: 46NVDFL6v5STw5Qw4j77PoBSHRTYnHZGZ8WRoGvHmpaMX7ZyhNUP2u24TLV9pNgncz1bZF2Vm8KkaNTzU7SXqrnFUx5zgHQ
文件(SHA-256)
| 文件 | SHA-256 | MD5 |
|---|---|---|
rootpacket.tar.gz(外层) | e2d0dab6b29df89d123fe8581047a03ac9b89ae8fa0d1f334b5aefbb93152857 | |
getroot | dda96d8a4bcc39dc7679347a4386bf1024152d2ccc46d333725ad0cda855d952 | |
xrandom(加壳) | ec3ef3dce99fa6cbc480f0f0b0c292676afed68704c44396271c7dc6afea2937 |
Build ID:getroot 148d8d902efd93ed892a541972fbcea3a99d05a3,xrandom d7a91225bdd2e3ab67cabded9d7809bcc724401f。
主机痕迹
| 路径 | 说明 |
|---|---|
/opt/kernel-kd/xrandom | 矿工二进制(root 模式) |
~/.xrandom/xrandom、~/.xrandom/run.sh | 矿工与启动器(用户态模式) |
/tmp/.xrandom.lock | PID 锁(用户态模式) |
/etc/systemd/system/kernel-kd.service | 恶意 systemd 单元 |
/usr/src/intel_uncore_freq_aux-1.2.0/ | rootkit 的 DKMS 源码 |
/sys/kernel/intel_uncore_freq/ | rootkit 的 sysfs 控制接口 |
/lib/modules/*/extra/intel_uncore_freq_aux.ko | 编译好的 rootkit 模块 |
行为特征
- 一个名为
xrandom、以 root 或当前用户身份运行的进程。 - 与硬件性能计数器(
perf stat)、或与风扇转速和功耗对不上的/proc/statCPU 数字。 - 一个 systemd 服务
kernel-kd(已启用,Type=simple,Restart=always)。 - 一条标记为
# xrandom-userland-autostart的 cron 条目。 - 一个在启动时加载、却不出现在
lsmod中的内核模块intel_uncore_freq_aux。
检测
如果 rootkit 未加载
systemctl status kernel-kd.service
ls -la /opt/kernel-kd/ ~/.xrandom/
dkms status | grep intel_uncore_freq
crontab -l | grep xrandom
lsmod | grep intel_uncore
如果 rootkit 已加载
用户态视图已被攻陷,因此检测必须来自 rootkit 之下或之旁:
- 用
perf stat把/proc/stat的 CPU 与硬件计数器对比。差距大就是破绽。 - 留意对
show_stat、meminfo_proc_show和iterate_dir的 ftrace 钩子。 - 把「报告出的 CPU」与「真实功耗、发热或风扇转速」之间的不一致,当作一个强信号。
捕获提权行为
- 一个并非已知加密工具(
cryptsetup、openssl、gpg、systemd-cryptsetup)的进程打开了一个AF_ALG、SOCK_SEQPACKET套接字,这是核心破绽。完整顺序是socket(AF_ALG)→bind→setsockopt(SOL_ALG)→accept→pipe→splice→sendmsg→splice→recvmsg(重复),然后execve(/usr/bin/su)。 - 把每个 SUID 二进制的磁盘字节与其页缓存视图对比。
sha256sum通过缓存读取,显示的是被破坏的副本,所以请用dd if=<file> iflag=direct直接读磁盘并对其求哈希,再做 diff。一个 SUID 二进制上的不匹配,就是页缓存破坏。
候选 YARA
rule Rootpacket_Cryptojacker
{
meta:
description = "Rootpacket Linux cryptojacking toolkit"
reference = "Kinryu Labs CTI 2026-06-16"
strings:
$wallet = "46NVDFL6v5STw5Qw4j77PoBSHRTYnHZGZ8WRoGvHmpaMX7ZyhNUP2u24TLV9pNgncz1bZF2Vm8KkaNTzU7SXqrnFUx5zgHQ" ascii
$svc = "kernel-kd" ascii
$cron = "xrandom-userland-autostart" ascii
$mod = "intel_uncore_freq_aux" ascii
condition:
$wallet or 2 of ($svc, $cron, $mod)
}
修复措施
- 从一个已知干净的状态移除 rootkit。 从 live 或恢复介质启动。删除
/lib/modules/*/extra/intel_uncore_freq_aux.ko*并运行dkms remove intel_uncore_freq_aux/1.2.0 --all,然后删除/usr/src/intel_uncore_freq_aux-1.2.0/并重建 initramfs(update-initramfs -u、dracut -f或mkinitcpio -P)。DKMS 条目必须清除,否则它会重建。 - 移除服务:
systemctl stop kernel-kd; systemctl disable kernel-kd; rm /etc/systemd/system/kernel-kd.service; systemctl daemon-reload。 - 移除矿工:
rm -rf /opt/kernel-kd/ ~/.xrandom/ /tmp/.xrandom.lock,然后pkill -9 -f xrandom。 - 清理 cron 中的
# xrandom-userland-autostart行。 - 恢复 killservice.sh 破坏的东西。 它对 Redis、Docker、PostgreSQL、MongoDB 及其他二进制设置了
chmod 000并添加了 iptables DROP 规则。请重装受影响的软件包并复查防火墙。 - 横向排查。 内层的
rootpacket.tar.gz是为再分发而打包的,所以请检查其他主机是否有相同指标,并审阅日志,查找killservice.sh中那些服务被利用的痕迹,以找到入口。 - 封堵 CVE-2026-31431。 升级到已修复的内核(6.18.22、6.19.12、7.0+,或你发行版的回合补丁)。在无法立即打补丁的地方,禁用脆弱的接口:
echo 'install algif_aead /bin/false' > /etc/modprobe.d/disable-algif-aead.conf,然后rmmod algif_aead。对于容器,在 seccomp 配置中封禁AF_ALG(family 38)。 - 从容器即推定主机失陷。 由于页缓存写入会跨越容器边界,请把任何运行过
setup.sh的主机(哪怕是从容器内部运行)都当作已完全失陷。重建主机,而不只是删除容器。
MITRE ATT&CK 映射
| 战术 | 技术 |
|---|---|
| 初始访问 | T1190 Exploit Public-Facing Application(Redis、Docker、MongoDB、Elasticsearch、Jenkins、Hadoop YARN,隐含) |
| 执行 | T1059.004 Unix Shell |
| 提权 | T1068 Exploitation for Privilege Escalation(CVE-2026-31431,AF_ALG algif_aead);T1611 Escape to Host(共享页缓存) |
| 持久化 | T1543.002 Systemd Service;T1053.003 Cron;T1547.006 Kernel Modules(DKMS) |
| 防御规避 | T1014 Rootkit;T1036.005 Masquerading: Match Legitimate Name;T1027.002 Software Packing(UPX);T1070.004 File Deletion;T1564.001 Hidden Files |
| 发现 | T1057 Process Discovery(猎杀对手) |
| 横向移动 | T1570 Lateral Tool Transfer(内层再分发包) |
| 影响 | T1496 Resource Hijacking(门罗币挖矿) |
方法论与分析师备注
- 分析主要为静态(字符串提取、反汇编、源码审阅、结构分析),在 Kali Linux x86-64 上进行。我们也在一台隔离虚拟机(内核 6.6.15)上运行过一次
getroot以观察其行为:它尝试了 AF_ALG 序列,在该构建上未拿到 root,并回退为以非特权方式运行命令。矿工未运行,也未上传任何东西。 - 提权组件被判定为 CVE-2026-31431,依据是绑定到 AF_ALG 套接字的
authencesn(hmac(sha256),cbc(aes))模板、/usr/bin/su这一页缓存目标,以及二进制中的splice/sendmsg/recvmsg写入循环。 - 样本(工具包及其各组件)可应其他研究者与防御方的请求提供。请发邮件至 [email protected],并简短说明你的身份以及索取用途。