1. Poorly-designed file upload functionality lead to RCE 2. Turned out the app was running in a container managed by #AzureKubernetesService (#AKS) 3. #Container was mounting a service account with permissions to deploy #pods in the same namespace
4. I deployed a new pod with hostPath root volume. Deployment was not blocked by any security policy. #Pod got deployed 5. I exec-ed into the pod's #container and escaped it through its hostPath volume. #privesc to the #AKS node succeeded!
6. Turned out the #AKS node had a #ManagedIdentity with read permissions on some #KeyVault secrets 7. One secret was a connection string providing read/write access to a #StorageAccount accessible from the Internet
8. Turned out the SA was used by multiple users for #CloudShell purposes 9. I downloaded the ".img" file associated with each account, mounted them locally, and modified their ".bashrc", so that a new access token for Graph was requested and sent to me next time they logged in
10. I re-uploaded the ".img" files to their corresponding user folders on the #StorageAccount and waited for users to login 11. Some access tokens came in 12. Turned out one of the #CloudShell users was #GlobalAdmin in the tenant 13. Game over ... 🤭
Mounting a #Kubernetes service account to a pod with permissions to deploy other pods implies that if your app has RCE, a threat actor will be able to infect other Services in the cluster (yes, even if you use strict PSPs) #KubernetesSecurity#k8s#aks#gke#eks #DevSecOps
🧵 👇
Background:
▪︎ A Service in #k8s is an object that balances HTTP requests between pods belonging to that Service
▪︎ A Service identifies its pods through a set of labels (e.g. "fancy-app: prod", "db: users", etc)
▪︎ A pod with a label associated with a Service will become part of that Service automatically
Attack scenario: 1. A pod is mounting a service account with permissions to deploy other pods 2. A container in the pod is running a vulnerable app, providing RCE to an attacker