Logo

Abusing docker.sock exposure


By Sheila A. Berta & Sol Ozzan

You have probably been playing with Docker vulnerabilities and realized that in real productive environments, sometimes containers need to bind mount the /var/run/docker.sock file for a variety of purposes. So...

What is the docker.sock file?

It is used to communicate with the main Docker daemon by the Docker API and the Docker CLI to execute Docker commands. This socket can also be used to communicate with the daemon from within a container.

The Docker daemon can listen for requests via three different types of sockets: Unix, tcp, and fd. By default, a Unix domain socket (or IPC socket) is created at /var/run/docker.sock.

A lot of Service Meshes like Consul, and System Monitoring Services like Newrelic and DataDog ask to mount /var/run/docker.sock to collect container information. For example, on DataDog the dd-agent user must have permissions to access the docker.sock to get real time logs that are indexed by default. Even in CI environments – like the ones that use Jenkins – the docker.sock must be exposed to the CI container, in order to give it the capability to start containers (specifically: build, run, sometimes push containers and images).

Searching GitHub for 'docker.sock' shows 267,932 matching results. This demonstrates the large number of projects publicly using this configuration to build a wide variety of clusters:


Bind mounting the Docker daemon socket gives a lot of power to a container, as it can control the daemon. It allows the container to communicate directly with the Docker daemon that runs on the host. Therefore, an attacker who compromises such a container can then take control of the whole cluster. Let's see how this is possible.

First of all, check that docker.sock is mounted inside the container. If so, it will be under the following path: /var/run/docker.sock – as previously explained.



In order to communicate with the docker.sock, the docker client must be installed inside the container.

 

Run apt-get install docker (Debian-based images) or apk add docker (Alpine-based images).

 

Inspecting the Swarm cluster

Below, some sample commands to get information about the Swarm cluster.

1) Run docker node ls to identify how many nodes are in the entire cluster.

In this environment there are 3 nodes (2 managers + 1 worker).

2) Run docker stack ls to know identify many stacks (services of an application) are running across all nodes.


3) Run docker service ls to get an overview of the services running across all nodes.

You can also run docker service inspect <service_name> to get details about a specific service (Mounts, IP, etc).

4) Run docker network ls to see all existing networks in the entire cluster.

You can also run docker network inspect <network_name> to get details about a specific network (IP range, driver, attached containers, etc).
Other useful commands are docker volume ls and docker secret ls to list the existing volumes and secrets respectively.

 

Getting a shell inside other containers

We can take advantage of the docker.sock exposure within the compromised container to obtain a shell in other containers running on the same node.


First, run docker container ls to see all the containers that are running on the node.

Choose one of the list and run docker container exec -it <container_id> /bin/bash to get an interactive shell inside such a container.

In case of Alpine-based images just use /bin/sh shell.

 

Node takeover

Finally, we can take control of the Docker host by creating a privileged instance of a container and mounting the host "/" filesystem on it.


Run the following command:


$ docker container run --rm -it --privileged --net=host --pid=host --volume /:/mnt nginx chroot /mnt




--privileged  runs the container as root and enables all system calls on the host.
--net=host  attaches the container to the host network interface, allowing us to reach other nodes on the cluster.
--pid=host allows processes within the container to see all of the processes on the host.


Additionally, we are binding the root (/) path of the host inside the container and making a chroot on it. 
In this way we can take control of the host by abusing the exposure of docker.sock inside a compromised container.

Taking this into account, if we now consider defence, it is recommended to reflect very carefully before using a Docker image that requires access to the Docker socket. Even with read-only permissions it exposes environments to additional risks.

 

Do you want to learn more?

https://dreamlab.net/en/education/trainings-schedule/ 

Sheila A. Berta
Head of Research at Dreamlab Technologies

Sol Ozzan
Security Researcher at Dreamlab Technologies

Abusing docker.sock exposure

All blog posts