Target Ports Details
The master API server https 443 The main server to interact with
The kubelet daemon https 10250, http 10255 10255 is unauth kubelet api. There are interesting "debug" endpoints, disabled by default in GKE but worth checking, more details later.
The kube-proxy daemon http 10256, http 30576 "Healthz" endpoint, responds to /healthz GET request.
The kube-dns daemon tcp/udp 53 No known issue but maybe you have a zero day!
"Monitor" daemon http 6061 Responds to /metrics GET requests.
Other pods running in the same node to be scanned All pods in a node share the same inet namespace/interface, also the same volume namespace.
Any "Services" exposing IPs/ports to be scanned "Services" in K8s terminology are basically load balancers.
GCP/GKE metadata web endpoint http 80 Metadata related to GKE/K8s, more about this later.
The idea is to see what can be seen/done first with the default service account configured on the pod, as this is our initial step into the cluster. Local "classic" unix privilege escalation may be useful but will certainly not help much being in the Pod (reminder: "Pod" is basically a running container in the case of GKE). By default in GKE, this service account has zero rights (well done Google, too bad for us :)! ) The default service account is configured in /var/run/secrets/kubernetes.io/serviceaccount or /run/secrets/kubernetes.io/serviceaccount. This is mounted by default (check with mount, you may be lucky and have multiple service accounts mounted or sensitive files) It contains:
/run/secrets/kubernetes.io/serviceaccount# ls
ca.crt namespace token
ca.crt: the cluster ca certificate namespace: the name of the namespace the service account is configured in token: the oauth token given to the service account to authenticate
Looking at environment variables should show where the API server is located:
# env
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_PORT=443
HOSTNAME=mypod
PWD=/run/secrets/kubernetes.io/serviceaccount
PKG_RELEASE=1~buster
HOME=/root
KUBERNETES_PORT_443_TCP=tcp://10.0.0.1:443
NJS_VERSION=0.3.9
TERM=xterm
SHLVL=1
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.0.0.1
KUBERNETES_SERVICE_HOST=10.0.0.1
KUBERNETES_PORT=tcp://10.0.0.1:443
KUBERNETES_PORT_443_TCP_PORT=443
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
NGINX_VERSION=1.17.9
_=/usr/bin/env
OLDPWD=/run/secrets/kubernetes.io/serviceaccount/..data
You can therefore use the kubectl binary you downloaded with the service account creds to start probing the master API server, for instance "ask" if you can list/create a pod (auth can-i command for kubectl):
# kubectl --token=`cat /run/secrets/kubernetes.io/serviceaccount/token` --certificate-authority=/run/secrets/kubernetes.io/serviceaccount/ca.crt -n `cat /run/secrets/kubernetes.io/serviceaccount/namespace` --server=https://$KUBERNETES_PORT_443_TCP_ADDR auth can-i create pods
Note: When running the kubectl binary without auth arguments, it will usually look for those default creds (but we sometimes have to explicitly pass them as arguments)
Querying non-authenticating endpoints If the default service account has not been modified and has no permissions, it can be interesting to query some endpoints that will answer un-authenticated queries. Some "metrics" type of endpoints (such as "heapster" on port 8082), will give some information about the pods/nodes available/running in the cluster. Also, the unauthenticated port of the kubelet daemon API (port 10255) will eventually answer to some requests. You should start port scanning the default subnet for open ports (don't forget 8082 and 10255) and try to "curl" them all.
Heapster
8082 is the default "heapster" port in GKE. If found, it will give you some basic, anonymous information such as:
/api/v1/model/namespaces/namespaces/ <-- which namespaces are available
/api/v1/model/nodes/ <-- list of the nodes
/api/v1/model/namespaces/{namespace-name}/pods/ <-- list of the pods in each namespace
# curl <http://10.8.1.3:8082/api/v1/model/namespaces/>
[
"default",
"kube-system"
]
# curl <http://10.8.1.3:8082/api/v1/model/namespaces/default/pods/>
[
"nginx",
"mypod"
]
For a more complete list of the REST urls, you may want to have a look there: https://github.com/kubernetes-retired/heapster/blob/master/docs/model.md
Kubelet (unauthenticated)
The kubelet API daemon, which is the primary agent running on each node to maintain the desired state of the pod, is potentially another source of information, listening on tcp 10255 for unauthenticated http requests. It contains really powerful debug endpoints (/run, /exec) which in the case of GKE should be disabled by default (that would be too easy..). It should however respond to some basic info requests (path taken from https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/server/server.go):
curl <http://10.8.1.1:10255/pods/>
curl <http://10.8.1.1:10255/stats/>
curl <http://10.8.1.1:10255/spec/>
curl <http://10.8.1.1:10255/metrics/>
/pods is the most interesting endpoint for an attacker, it contains quite a bit of information about pods, IP addresses, container names, secret names, and url paths.
Metrics The GKE "metrics-server" is another metrics related server but is requesting authentication by default (listening on port 443). It is worth trying but will probably not be open anonymously (you can try some REST URLs from the API metrics design at https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/resource-metrics-api.md).
What to look for
There is a lot of information to gather/compile from all those endpoints. During your investigation (and when you manage to escalate to any new service account, more about this in next paragraphs), you basically want to search for: In all namespaces: