July 14, 2026
WhereCTF — Docker Forensics Challenge
Challenge: netanix/wherectf:latest

By ecstasyyy
1 min read
Initial Recon
Pulled and extracted all 15 Docker image layers from the OCI manifest. The base image was Ubuntu 22.04 with coreutils, procps, gcc, cron, and xxd installed. The entrypoint was /bin/sh /fallbackpoint.sh, which starts three background daemons as root then drops to ctfuser.
Fake Flags (5 decoys)
Five fake flags were planted in obvious locations, all explicitly containing "fake" in their content:
/tmp/flags/flag.txt--softwarica{fake_n1c3_try_wr0ng_pl4c3}/tmp/ hidden/data.txt--softwarica{fake_cl0s3_but_n0_c1g4r}/tmp/.cache/flag.txt--softwarica{fake_keep_hunt1ng_buddy}/var/tmp/.backup/backup.dat--softwarica{fake_d1str4ct10n_max}/home/ctfuser/.secret/secret.txt--softwarica{fake_y0u_w1sh_th1s_w4s_1t}
Key Artifacts Discovered
1. Root Password via Hex Encoding
A .locale.dat file at /usr/share/locale/en_US/LC_MESSAGES/.cache/.config/system/ contained the hex string 526f30745f50407373773072645f48316464336e5f44333370210a. Decoding this gave: Ro0t_P@ssw0rd_H1dd3n_D33p!
The Docker history confirmed this was the root password set during build.
2. system_daemon Binary Analysis
The binary at /usr/local/sbin/system_daemon (compiled from flag_daemon.c disclosed in the Docker history) does the following:
- Closes stdin/stdout/stderr and reopens them to
/dev/null(daemonization) - Opens
/tmp/.flag_datawith O_RDWR | O_CREAT, mode 0600 - Writes the flag to the file
- Seeks back to the beginning
- Deletes the file with
unlink() - Dups the fd to fd 3 if not already there
- Sleeps for 1 hour in a loop
The file is deleted from the directory tree, but the data remains accessible through the open file descriptor at /proc/<pid>/fd/3 as long as the process lives.
3. Defenses
- root_guardian (cron job every minute): A script that scans for root-owned
shprocesses and SIGKILLs any whose parent isn'tsu,login, PID 0, or PID 1. This blocks unauthorized root shells but allows legitimatesu. - ps/top replaced: Both are shell wrappers that check
id -uand refuse to run unless root. The real binaries are atps.real/top.real. - No bash: Only
/bin/shis available (ashvariant). - sudo disabled: Configuration allows only 3 tries with no password caching.
The Flag Retrieval Technique
The flag's content (pr0c3ss_fd_m4st3r_r00t_pwn3r = "process fd master root pwner") hints at the technique: access the deleted file through the still-open file descriptor in /proc.
In the live container:
# Option A: su to root then read through the daemon's fd
su -
# password: Ro0t_P@ssw0rd_H1dd3n_D33p!
cat /proc/$(pidof system_daemon)/fd/3
# Option B: As ctfuser, iterate all processes' fd 3
cat /proc/*/fd/3# Option A: su to root then read through the daemon's fd
su -
# password: Ro0t_P@ssw0rd_H1dd3n_D33p!
cat /proc/$(pidof system_daemon)/fd/3
# Option B: As ctfuser, iterate all processes' fd 3
cat /proc/*/fd/3The flag is redacted
Summary
This challenge demonstrates a classic forensics technique: files deleted via unlink() remain recoverable through open file descriptors in /proc/<pid>/fd/. The challenge builder hid the real flag behind this mechanism while seeding 5 fake flags as decoys and implementing layered defenses (restricted ps/top, root_guardian, no bash) to simulate a hardened container environment.