Docker escape using mounted docker.sock
Docker socket is a UNIX socket that acts as a backbone for managing your containers. When you type any Docker commands using your doctor client, your Docker client basically interacts with this Docker socket and manages your containers.
When you download Docker images from the Docker Hub and when you start containers using those images, the developer of the image may ask you to mount /var/run/docker.sock into the container. This may be required for some legitimate reasons, but we should be aware of the dangers that this feature brings with it.
Some of the legitimate reasons could be, you are starting a container and you want to manage other containers from that container, and obviously it requires access to your Docker socket. Similarly, you are running a tool that is going to audit all your doctor containers running on the host. When you are running this tool as a docker container obviously it needs to access Docker socket to be able to interact with other containers running on your host. While these are some of the legitimate reasons to have docker.sock mounted on your container, as mentioned earlier we should always be aware of the dangers that it brings.
Container escape using docker.sock
Let us see an example of how this feature can be abused.
Let us assume that as an attacker we have gotten a shell on a container where docker.sock is mounted. With that assumption, we are only inside the container and we have a docker.sock mounted onto the container. Using this access, our goal is to be able to access a file that is on the host machine and accessible only by the root user. We will try to access the file named crackme.txt which is present inside the root directory on the host machine.
Let us first create a directory called dockersock and change our working directory to dockersock using the following command.
~$ mkdir dockersock
~$ cd dockersock
Now, let us simulate the attack by obtaining a shell on a container, and let’s make sure that docker.sock is mounted onto the container. To do that, we will be using the alpine image and we are going to spin up a container using the following command.
~$ docker run -itd -v /var/run/docker.sock:/var/run/docker.sock alpine
In the preceding command, we can see that we are using the docker run command and mounting the /var/run/docker.sock onto the container using -v.
From the preceding image, we can see that the container has started. Let us use the docker ps command to get the container id.
From the preceding image, we can see that the container id is 3570ce8a4068. Let us use the following command to get a shell on the container.
~$ docker exec -it 3570ce8a4068
Let us confirm that we have docker.sock mounted onto the container. To do that let us type the following command.
~$ ls /var/run/docker.sock
It looks as follows on the container shell.
The preceding image confirms that docker.sock has been mounted onto the container. To be able to use this docker socket, we need to have Docker client installed on this container. Let us check if the docker socket is already available on the alpine image by typing docker. We get the following output.
From the preceding image, we can see that docker client is not available. Before we install docker client, let us do apk update using the following command.
/# apk update
Now, let us type the following command to install docker client onto the container.
~$ apk add -U docker
We get the following output.
Docker installation is now complete, and we should be able to run docker commands. Using this docker client and the docker socket mounted onto the container, we can simply spin up another container on the host and mount the root directory of the host machine onto the newly started container and then get a shell on the newly started container to be able to access the root directory of the host. To do that, let us type the following command.
~$ docker -H unix:///var/run/docker.sock run -it -v /:/test:ro -t alpine sh
In the above command, we have specified the location of docker.sock which is /var/run/docker.sock and used -v to be able to mount the root directory of the host under the container that we are now starting and we named it test on the container. So, the root directory of the host machine is going to be mounted into a directory called test on the container. Finally, we pass sh as an argument so that we will directly get a shell on the container that we are now starting.
The command should run successfully as shown below.
Let us navigate to the test folder as this is where we have mounted the root directory of the host machine and change the directory to root and type ls as shown in the following figure.
This is the indication that we have gotten foothold onto the host machine’s file system. Let us now check the contents of the crackme.txt file using the cat command.
This is how we can docker.sock which is mounted onto the container can be abused to be able to gain foothold onto the docker host.
Docker containers are being heavily used in the IT industry and it is extremely important to be aware of some of the security sensitive features they come with as they may pose serious security risk to the organizations when exploited.
If you like to learn more about docker security check out our course on “Hacking and Securing Docker Containers”