What Are We Doing
In my recent escapades of testing various workflow engines I eventually found and grew fond of Argo. Argo Workflows is an open source container-native workflow engine for orchestrating parallel jobs on Kubernetes. Argo Workflows is implemented as a Kubernetes CRD. What does this mean? Basically you can define jobs via a yaml file and have it execute docker containers. It is more common than not for Argo to be able to run privileged containers and this is precisely what we intend to exploit.
One of Argo’s features is the ability to run a privileged container just as you might when using Docker outside of Kubernetes or Argo. When using this --privileged
flag containers have root privileges on the host machine, containers have full access to all devices, and not under restrictions from AppArmor, seccomp, or other security features of some Linux distributions. In addition to all that the usage of the --privileged
flag introduces the potential for a container escape allowing us to run arbitrary code on the host machine allowing an attacker to take over a target machine.
Setup
For the purposes of this post I have setup the following:
- Argo server running @
10.0.0.2
(known later astarget
) - Attacker server running @
10.0.0.3
(known later asattacker
)
For the purposes of this example imagine
target
is exposing Argo on the internet on it's public IP.
Argo Container to Root — How?
So now we know what our setup looks like and what Argo is mainly used for. But what about the exploit? How do we get the code that runs inside of the container to execute on the host? Well Trail of Bits did an amazing post on this exact technique (in fact it’s where I learned it). Some of the information below is taken from there for easy reading.
Requirements to use this technique
According to Trail of Bits, in fact, --privileged
provides far more permissions than needed to escape a docker container via this method. In reality, the "only" requirements are:
- We must be running as root inside the container