Cluster Administrator Privilege Escalation in GKE Autopilot

We discussed this vulnerability as part of our weekly podcast on 15 March 2022

Escaping to the Node Virtual Machine The first step in the chain was going from container automation scripts run within and accessing the node virtual machine. What they found was there was an allow list of workloads (based on image name and command) that could mount certain host paths.

Specifically a container with an image named* and the command bash -c could mount (read-only), /proc and /var/run/containerd. This check could by bypassed by providing custom arguments to the container under args rather than as part of command. So you control the code bash will execute inside the datadog image.

As the containerd socket can be mounted inside this image, an attacker can abuse that access to create a new privileged container with full access to the host filesystem. Then, install a systemd service to spawn a reverse shell with full access to the virtual machine including other tenants and their service account tokens and instance metadata. The attacker also gains access to the Kubelet’s credentials.

Full Cluster Takeover

The authors used their toolsa-hunter to find powerful pods to compromise. Found the kube-system namespace which is highly privileged (no restrictions) and two pods that are installed by default. So the first step would be to compromise a node virtual machine that is running one of the privileged pods, steal their service account token from the node.

With the service account token one can update an existing deployment’s service account, add a malicious container to the deployment, and read the /run/secrets/

Bonus: Invisible Backdoor

A little added bonus to end off the attack, they also document a way of backdooring the system by installing a MutatingAdmissionWebhook which will be called whenever an objects are created or updated in the kubernetes cluster. Giving access to all the pods and secrets and can mutate them. Autopilot admins cannot even list these webhooks and so cannot discover them.