Docker API Container Escape
Unauthenticated Docker API access enables launching a new container with the host filesystem mounted inside it. Since the Docker daemon runs as root, the new container has full read-write access to every file on the host. Combining this with nsenter (a tool for entering Linux namespaces) produces a root shell on the host system outside any container boundary. This is the primary exploitation path for exposed Docker API and consistently appears on HTB machines and real-world engagements. Confirm unauthenticated access through unauthenticated access assessment first.
- Method 1: Mount Host Filesystem and Read Sensitive Files
- Method 2: Get a Reverse Shell on the Host with nsenter
- Method 3: Write SSH Key to Host
- Method 4: Via the REST API Without the Docker CLI
Method 1: Mount Host Filesystem and Read Sensitive Files
Start a container with the host root filesystem mounted at /host. Use any image already present on the target to avoid a slow pull:
nginx:latest mysql:8.0 ubuntu:22.04
root@a1b2c3d4e5f6:/#
The chroot /host makes the container session behave as if it is running directly on the host filesystem. You now have a root shell on the host. Read /etc/shadow, SSH keys, and any other sensitive files:
root:$6$abc123$hashedpassword:19000:0:99999:7:::
-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXk...
Method 2: Get a Reverse Shell on the Host with nsenter
nsenter enters the PID 1 namespace on the host: stepping fully outside any container isolation:
--pid=host shares the host PID namespace with the container. nsenter -t 1 enters all namespaces of PID 1 (the host init process). The resulting shell is running on the host with full root privileges, not inside any container.
Method 3: Write SSH Key to Host
Plant an SSH public key in root's authorized_keys for persistent access without a reverse shell:
root@docker-host-01:~#
Important
Remove any planted SSH keys before engagement close. Document the exact key fingerprint and the path it was written to. Planted keys persist until explicitly removed.
Method 4: Via the REST API Without the Docker CLI
When the docker CLI is not available on the attack machine, perform the same attack using raw API calls:
"Id": "c1d2e3f4a5b6..."
root:$6$abc123$hashedpassword:19000:0:99999:7:::
References
-
Docker Engine APIDOCS: Docker Engine API, docs.docker.com/engine/api (opens in new tab)
Container create, start, and logs API reference
-
nsenter(1) manualMAN: nsenter(1) manual, man7.org/linux/man-pages/man1/nsenter.1.html (opens in new tab)
Namespace entry: pid, mount, uts, ipc, net options