Cross-Account Container Takeover in Azure Container Instances

We discussed this vulnerability during Episode 81 on 13 September 2021

tl;dr Cool chain to escape and impact other containers on Azure Container Instances hosted by Kubernetes clusters (some are hosted by Service Fabric Clusters which are not vulnerable in this way), first is the container escape itself into the containing node/vm, followed by a leaked JWT useful to run commands against all nodes in the cluster.

Container Escape

The post starts off with some background on Azure Container Instances, and talks about WhoC a container they developed and released in August at Defcon 29. Which uses a neat trick to disclose the container runtime binary to a remote server. You can read the details on the WhoC Github but the gist is re-executing /proc/self/exe inside the container and replacing the dynamic linker to pass execution to something to exfil it.

Using that they discover that it is using a very old versions of runC from late 2016 to late 2017. These have known vulnerabilities, so escaping the container is straight forward.

Cross-Node Interaction

They include a semi-rabbit hole into thinking that the cluster’s apiserver is vulnerable to another known vulnerability. The vulnerability involves redirecting requests from the apiserver to another node, so redirect an exec to another note to exec on it. As long as you cna issue the exec to your node, you can redirect it it.

It turns out while the API server was potentially vulnerable to this, issued execs actually came from another server, the bridge, that was not vulnerable. While the known vuln was a rabbit hole, what they discovered was that requests from the bridge included an Authorization header with a JWT. This JWT had pods/exec privileges across the entire cluster, including the API server. With apiserver access, the entire cluster can be compromised.

Server Side Request Forgery in pods bridge

After reporting the first issue, they then discovered another attack on the pods bridge which would lead to the same kind of compromise. When the bridge constructs the request for an exec command from a pod, it takes the node IP from the customer pod’s status.hostIP field. This field could be controlled by an attacker and continuously overwritten to circumvent the api server’s continuous correction of the field. On it’s own, this wouldn’t have been useful for an attacker because the URL would still point to your pod’s namespace even if the request was directed to a different pod’s IP.

However, this field wasn’t validated to make sure it was even a proper IP address, it could be any arbitrary string, including URL components. This gives you an injection into the request URL, which you can use to trick the bridge into executing a command on the API server container instead of your own.