mirror of
https://github.com/carlospolop/hacktricks
synced 2025-01-08 11:18:52 +00:00
352 lines
9.6 KiB
Markdown
352 lines
9.6 KiB
Markdown
# 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**](./#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](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server):
|
||
|
||
_“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**](./#cluster-hardening-rbac).
|
||
|
||
## Enumeration CheatSheet
|
||
|
||
To enumerate the environment you can upload the [**kubectl**](https://kubernetes.io/es/docs/tasks/tools/install-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:
|
||
|
||
```text
|
||
GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}
|
||
```
|
||
|
||
If you have the **`list`** permission, you are allowed to execute these API requests:
|
||
|
||
```bash
|
||
#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 these API requests:
|
||
|
||
```text
|
||
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\).
|
||
|
||
|
||
|
||
{% hint style="danger" %}
|
||
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`
|
||
{% endhint %}
|
||
|
||
### Get namespaces
|
||
|
||
{% tabs %}
|
||
{% tab title="kubectl" %}
|
||
```bash
|
||
./kubectl get namespaces
|
||
```
|
||
{% endtab %}
|
||
|
||
{% tab title="API" %}
|
||
```bash
|
||
curl -v -H "Authorization: Bearer <jwt_token>" \
|
||
https://<Kubernetes_API_IP>:<port>/api/v1/namespaces/
|
||
```
|
||
{% endtab %}
|
||
{% endtabs %}
|
||
|
||
### Get secrets
|
||
|
||
{% tabs %}
|
||
{% tab title="kubectl" %}
|
||
```text
|
||
./kubectl get secrets -o yaml
|
||
./kubectl get secrets -o yaml -n custnamespace
|
||
```
|
||
{% endtab %}
|
||
|
||
{% tab title="API" %}
|
||
```bash
|
||
curl -v -H "Authorization: Bearer <jwt_token>" \
|
||
https://<Kubernetes_API_IP>:<port>/api/v1/namespaces/default/secrets/
|
||
|
||
curl -v -H "Authorization: Bearer <jwt_token>" \
|
||
https://<Kubernetes_API_IP>:<port>/api/v1/namespaces/custnamespace/secrets/
|
||
```
|
||
{% endtab %}
|
||
{% endtabs %}
|
||
|
||
If you can read secrets you can use the following lines to get the privileges related to each to token:
|
||
|
||
```bash
|
||
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
|
||
```
|
||
|
||
### Get Current Privileges
|
||
|
||
{% tabs %}
|
||
{% tab title="kubectl" %}
|
||
```bash
|
||
./kubectl auth can-i --list #Get privileges in general
|
||
./kubectl auth can-i --list -n custnamespace #Get privileves in custnamespace
|
||
```
|
||
{% endtab %}
|
||
{% endtabs %}
|
||
|
||
**Once you know which privileges** you have, check the following page to figure out **if you can abuse them** to escalate privileges:
|
||
|
||
{% page-ref page="hardening-roles-clusterroles.md" %}
|
||
|
||
### Get Current Context
|
||
|
||
{% tabs %}
|
||
{% tab title="Kubectl" %}
|
||
```text
|
||
kubectl config current-context
|
||
```
|
||
{% endtab %}
|
||
{% endtabs %}
|
||
|
||
### Get deployments
|
||
|
||
{% tabs %}
|
||
{% tab title="kubectl" %}
|
||
```text
|
||
./kubectl get deployments
|
||
./kubectl get deployments -n custnamespace
|
||
```
|
||
{% endtab %}
|
||
|
||
{% tab title="API" %}
|
||
```bash
|
||
curl -v -H "Authorization: Bearer <jwt_token>" \
|
||
https://<Kubernetes_API_IP>:<port>/api/v1/namespaces/default/deployments/
|
||
|
||
curl -v -H "Authorization: Bearer <jwt_token>" \
|
||
https://<Kubernetes_API_IP>:<port>/api/v1/namespaces/custnamespace/deployments/
|
||
```
|
||
{% endtab %}
|
||
{% endtabs %}
|
||
|
||
### Get pods
|
||
|
||
{% tabs %}
|
||
{% tab title="kubectl" %}
|
||
```text
|
||
./kubectl get pods
|
||
./kubectl get pods -n custnamespace
|
||
```
|
||
{% endtab %}
|
||
|
||
{% tab title="API" %}
|
||
```bash
|
||
curl -v -H "Authorization: Bearer <jwt_token>" \
|
||
https://<Kubernetes_API_IP>:<port>/api/v1/namespaces/default/pods/
|
||
|
||
curl -v -H "Authorization: Bearer <jwt_token>" \
|
||
https://<Kubernetes_API_IP>:<port>/api/v1/namespaces/custnamespace/pods/
|
||
```
|
||
{% endtab %}
|
||
{% endtabs %}
|
||
|
||
### Get services
|
||
|
||
{% tabs %}
|
||
{% tab title="kubectl" %}
|
||
```text
|
||
./kubectl get services
|
||
./kubectl get services -n custnamespace
|
||
```
|
||
{% endtab %}
|
||
|
||
{% tab title="API" %}
|
||
```bash
|
||
curl -v -H "Authorization: Bearer <jwt_token>" \
|
||
https://<Kubernetes_API_IP>:<port>/api/v1/namespaces/default/services/
|
||
|
||
curl -v -H "Authorization: Bearer <jwt_token>" \
|
||
https://<Kubernetes_API_IP>:<port>/api/v1/namespaces/custnamespace/services/
|
||
```
|
||
{% endtab %}
|
||
{% endtabs %}
|
||
|
||
### Get nodes
|
||
|
||
{% tabs %}
|
||
{% tab title="kubectl" %}
|
||
```text
|
||
./kubectl get nodes
|
||
```
|
||
{% endtab %}
|
||
|
||
{% tab title="API" %}
|
||
```bash
|
||
curl -v -H "Authorization: Bearer <jwt_token>" \
|
||
https://<Kubernetes_API_IP>:<port>/api/v1/nodes/
|
||
```
|
||
{% endtab %}
|
||
{% endtabs %}
|
||
|
||
### Get daemonsets
|
||
|
||
{% tabs %}
|
||
{% tab title="kubectl" %}
|
||
```text
|
||
./kubectl get daemonsets
|
||
```
|
||
{% endtab %}
|
||
|
||
{% tab title="API" %}
|
||
```bash
|
||
curl -v -H "Authorization: Bearer <jwt_token>" \
|
||
https://<Kubernetes_API_IP>:<port>/apis/extensions/v1beta1/namespaces/default/daemonsets
|
||
```
|
||
{% endtab %}
|
||
{% endtabs %}
|
||
|
||
### Get "all"
|
||
|
||
{% tabs %}
|
||
{% tab title="kubectl" %}
|
||
```text
|
||
./kubectl get all
|
||
```
|
||
{% endtab %}
|
||
{% endtabs %}
|
||
|
||
## **Pod Breakout**
|
||
|
||
**If you are lucky enough you may be able to escape from it to the node:**
|
||
|
||
![](https://sickrov.github.io/media/Screenshot-161.jpg)
|
||
|
||
{% page-ref page="../../linux-unix/privilege-escalation/docker-breakout.md" %}
|
||
|
||
## 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 <a id="create-a-sidecar-proxy-app"></a>
|
||
|
||
Create your .yaml
|
||
|
||
```bash
|
||
kubectl run app --image=bash --comand -oyaml --dry-run=client > <appName.yaml> -- shj -c 'ping google.com'
|
||
```
|
||
|
||
Edit your .yaml and add the uncomment lines:
|
||
|
||
```yaml
|
||
#apiVersion: v1
|
||
#kind: Pod
|
||
#metadata:
|
||
# name: security-context-demo
|
||
#spec:
|
||
# securityContext:
|
||
# runAsUser: 1000
|
||
# runAsGroup: 3000
|
||
# fsGroup: 2000
|
||
# volumes:
|
||
# - name: sec-ctx-vol
|
||
# emptyDir: {}
|
||
# containers:
|
||
# - name: sec-ctx-demo
|
||
# image: busybox
|
||
command: [ "sh", "-c", "apt update && apt install iptables -y && iptables -L && sleep 1h" ]
|
||
securityContext:
|
||
capabilities:
|
||
add: ["NET_ADMIN"]
|
||
# volumeMounts:
|
||
# - name: sec-ctx-vol
|
||
# mountPath: /data/demo
|
||
# securityContext:
|
||
# allowPrivilegeEscalation: true
|
||
```
|
||
|
||
See the logs of the proxy:
|
||
|
||
```bash
|
||
kubectl logs app -C proxy
|
||
```
|
||
|
||
More info at: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)
|
||
|
||
## 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:**
|
||
|
||
```text
|
||
kubectl get svc –all-namespaces
|
||
```
|
||
|
||
![](../../.gitbook/assets/image%20%28471%29.png)
|
||
|
||
### Scanning
|
||
|
||
The following Bash script \(taken from a [Kubernetes workshop](https://github.com/calinah/learn-by-hacking-kccn/blob/master/k8s_cheatsheet.md)\) will install and scan the IP ranges of the kubernetes cluster:
|
||
|
||
```bash
|
||
sudo apt-get update
|
||
sudo apt-get install nmap
|
||
nmap-kube ()
|
||
{
|
||
nmap --open -T4 -A -v -Pn -p 443,2379,8080,9090,9100,9093,4001,6782-6784,6443,8443,9099,10250,10255,10256 "${@}"
|
||
}
|
||
nmap-kube-discover () {
|
||
local LOCAL_RANGE=$(ip a | awk '/eth0$/{print $2}' | sed 's,[0-9][0-9]*/.*,*,');
|
||
local SERVER_RANGES=" ";
|
||
SERVER_RANGES+="10.0.0.1 ";
|
||
SERVER_RANGES+="10.0.1.* ";
|
||
SERVER_RANGES+="10.*.0-1.* ";
|
||
nmap-kube ${SERVER_RANGES} "${LOCAL_RANGE}"
|
||
}
|
||
nmap-kube-discover
|
||
```
|
||
|
||
## References
|
||
|
||
{% embed url="https://www.cyberark.com/resources/threat-research-blog/kubernetes-pentest-methodology-part-3" %}
|
||
|