Kubernetes Enumeration
- If you want to see your company advertised in HackTricks or if you want access to the latest version of the PEASS or download HackTricks in PDF Check the SUBSCRIPTION PLANS!
If you have compromised access to a machine the user may have access to some Kubernetes platform. The token is usually located in a file pointed by the env var
KUBECONFIG
or inside ~/.kube
.In this folder you might find config files with tokens and configurations to connect to the API server. In this folder you can also find a cache folder with information previously retrieved.
If you have compromised a pod inside a kubernetes environment, there are other places where you can find tokens and information about the current K8 env:
Before continuing, if you don't know what is a service in Kubernetes I would suggest you to follow this link and read at least the information about Kubernetes architecture.
“When you create a pod, if you do not specify a service account, it is automatically assigned the default service account in the same namespace.”
ServiceAccount is an object managed by Kubernetes and used to provide an identity for processes that run in a pod.
Every service account has a secret related to it and this secret contains a bearer token. This is a JSON Web Token (JWT), a method for representing claims securely between two parties.
Usually one of the directories:
/run/secrets/kubernetes.io/serviceaccount
/var/run/secrets/kubernetes.io/serviceaccount
/secrets/kubernetes.io/serviceaccount
contain the files:
- ca.crt: It's the ca certificate to check kubernetes communications
- namespace: It indicates the current namespace
- token: It contains the service token of the current pod.
Now that you have the token, you can find the API server inside the environment variable
KUBECONFIG
. For more info run (env | set) | grep -i "kuber|kube
"
The service account token is being signed by the key residing in the file sa.key and validated by sa.pub.
Default location on Kubernetes:
- /etc/kubernetes/pki
Default location on Minikube:
- /var/lib/localkube/certs
Hot pods are pods containing a privileged service account token. A privileged service account token is a token that has permission to do privileged tasks such as listing secrets, creating pods, etc.
If you don't know what is RBAC, read this section.
In order to enumerate a K8s environment you need a couple of this:
- A valid authentication token. In the previous section we saw where to search for a user token and for a service account token.
- The address (https://host:port) of the Kubernetes API. This can be usually found in the environment variables and/or in the kube config file.
- Optional: The ca.crt to verify the API server. This can be found in the same places the token can be found. This is useful to verify the API server certificate, but using
--insecure-skip-tls-verify
withkubectl
or-k
withcurl
you won't need this.
With those details you can enumerate kubernetes. If the API for some reason is accessible through the Internet, you can just download that info and enumerate the platform from your host.
However, usually the API server is inside an internal network, therefore you will need to create a tunnel through the compromised machine to access it from your machine, or you can upload the kubectl binary, or use
curl/wget/anything
to perform raw HTTP requests to the API server.With
get
permissions you can access information of specific assets (describe
option in kubectl
) API:GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}
If you have the
list
permission, you are allowed to execute API requests to list a type of asset (get
option in kubectl
):#In a namespace
GET /apis/apps/v1/namespaces/{namespace}/deployments
#In all namespaces
GET /apis/apps/v1/deployments
If you have the
watch
permission, you are allowed to execute API requests to monitor assets:GET /apis/apps/v1/deployments?watch=true
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments?watch=true
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments/{name} [DEPRECATED]
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments [DEPRECATED]
GET /apis/apps/v1/watch/deployments [DEPRECATED]
They open a streaming connection that returns you the full manifest of a Deployment whenever it changes (or when a new one is created).
The following
kubectl
commands indicates just how to list the objects. If you want to access the data you need to use describe
instead of get
From inside a pod you can use several env variables:
export APISERVER=${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS}
export SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
export NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
export TOKEN=$(cat ${SERVICEACCOUNT}/token)
export CACERT=${SERVICEACCOUNT}/ca.crt
alias kurl="curl --cacert ${CACERT} --header \"Authorization: Bearer ${TOKEN}\""
# if kurl is still got cert Error, using -k option to solve this.
By default the pod can access the kube-api server in the domain name
kubernetes.default.svc
and you can see the kube network in /etc/resolv.config
as here you will find the address of the kubernetes DNS server (the ".1" of the same range is the kube-api endpoint).Having the token and the address of the API server you use kubectl or curl to access it as indicated here:
By default, The APISERVER is communicating with
https://
schemaalias k='kubectl --token=$TOKEN --server=https://$APISERVER --insecure-skip-tls-verify=true'
if nohttps://
in url, you may get Error Like Bad Request.
You can find an official kubectl cheatsheet here. The goal of the following sections is to present in ordered manner different options to enumerate and understand the new K8s you have obtained access to.
To find the HTTP request that
kubectl
sends you can use the parameter -v=8
# Launch burp
# Set proxy
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080
# Launch kubectl
kubectl get namespace --insecure-skip-tls-verify=true
Kubectl
kubectl config get-users
kubectl config get-contexts
kubectl config get-clusters
kubectl config current-context
# Change namespace
kubectl config set-context --current --namespace=<namespace>
If you managed to steal some users credentials you can configure them locally using something like:
kubectl config set-credentials USER_NAME \
--auth-provider=oidc \
--auth-provider-arg=idp-issuer-url=( issuer url ) \
--auth-provider-arg=client-id=( your client id ) \
--auth-provider-arg=client-secret=( your client secret ) \
--auth-provider-arg=refresh-token=( your refresh token ) \
--auth-provider-arg=idp-certificate-authority=( path to your ca certificate ) \
--auth-provider-arg=id-token=( your id_token )
With this info you will know all the services you can list
kubectl
k api-resources --namespaced=true #Resources specific to a namespace
k api-resources --namespaced=false #Resources NOT specific to a namespace
kubectl
API
k auth can-i --list #Get privileges in general
k auth can-i --list -n custnamespace #Get privileves in custnamespace
# Get service account permissions
k auth can-i --list --as=system:serviceaccount:<namespace>:<sa_name> -n <namespace>
kurl -i -s -k -X $'POST' \
-H $'Content-Type: application/json' \
--data-binary $'{\"kind\":\"SelfSubjectRulesReview\",\"apiVersion\":\"authorization.k8s.io/v1\",\"metadata\":{\"creationTimestamp\":null},\"spec\":{\"namespace\":\"default\"},\"status\":{\"resourceRules\":null,\"nonResourceRules\":null,\"incomplete\":false}}\x0a' \
"https://$APISERVER/apis/authorization.k8s.io/v1/selfsubjectrulesreviews"
Another way to check your privileges is using the tool: https://github.com/corneliusweig/rakkess****
You can learn more about Kubernetes RBAC in:
Once you know which privileges you have, check the following page to figure out if you can abuse them to escalate privileges:
kubectl
API
k get roles
k get clusterroles
kurl -k -v "https://$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/roles?limit=500"
kurl -k -v "https://$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/clusterroles?limit=500"
Kubernetes supports multiple virtual clusters backed by the same physical cluster. These virtual clusters are called namespaces.
kubectl
API
k get namespaces
kurl -k -v https://$APISERVER/api/v1/namespaces/
kubectl
API
k get secrets -o yaml
k get secrets -o yaml -n custnamespace
kurl -v https://$APISERVER/api/v1/namespaces/default/secrets/