Home > Writeups > WHAMazon! Web 4 - The Archives

WHAMazon! Web 4 - The Archives

Chaining prior recon from robots.txt with API endpoint fuzzing and a missing-result anomaly to discover a path traversal vulnerability in an image file server.

The Archives

Challenge Description

Warehouse incident reports are kept in a separate directory. The file server was built quickly. Corners were cut.

Flag: Raptor{flag4_p4th_tr4v3rs4l_d1r3ct0ry_3sc4p3}


Following Prior Recon

The mention of incident reports was an immediate callback to Web 1: /api/internal/incidents was sitting right there in robots.txt. Visiting it:

{
  "classified": true,
  "message": "Access to incident logs requires Level 5 clearance. Contact your WHAM! supervisor.",
  "recent_count": 47,
  "suppressed_count": 44
}

Locked behind clearance. The flavor text said "separate directory" and "file server built quickly", that's a nudge toward path traversal. Tried the obvious:

/api/internal/incidents/../../../../flag.txt

404. The incidents endpoint wasn't the attack surface, it was just the hint pointing at the theme. Time to go broader.


API Enumeration with ffuf

Ran ffuf against the base /api/ path with the SecLists API endpoints list:

ffuf -w /usr/share/seclists/Discovery/Web-Content/api/api-endpoints-deep.txt \
     -u https://whamazon.strayerraptors.com/api/FUZZ

Got hits back, but two things stood out immediately:

1. /api/jobs was returning unusually low word count compared to every other result, likely minimal or empty responses worth investigating. And/api/cart was returning a 401, likely just because no Cookie was provided.

2. We only got 275 results when the wordlist has 276 lines. One endpoint wasn't returning anything. No 200, 404, nothing registering in the output.

So I pulled the results into LibreOffice Calc and did a diff against the full wordlist. The missing entry: /api/images.

No response at all from ffuf which meant it was probably being filtered or timing out under specific conditions, not that it didn't exist. Visiting it directly confirmed it:

{"message": "Missing 'file' parameter"}

The endpoint is alive and expecting a file parameter. A file server that takes a filename as a parameter and was built quickly with corners cut, that's got path traversal written all over it.


Exploitation

/api/images/?file=../../../flag.txt
Raptor{flag4_p4th_tr4v3rs4l_d1r3ct0ry_3sc4p3}

The file parameter was being passed directly to a file read operation with no sanitization, allowing traversal out of the intended directory using ../ sequences.


The Missing Result Anomaly

It is worth calling this out specifically because it could have been easy to miss. When fuzzing, a missing result is just as interesting as an unexpected one. In this case /api/images was silently absent from ffuf output, possibly due to a timeout, an unusual response format, or a response code that didn't match the filter. Always cross-reference your results against the source wordlist, especially when the math doesn't math.


Key Takeaways

Path traversal happens when user-controlled input is used to construct a filesystem path without validation. The fix is straightforward: resolve the canonical path of the requested file and verify it falls within the intended base directory before serving it. Something like:

import os

BASE_DIR = "/var/www/images"
requested = os.path.realpath(os.path.join(BASE_DIR, user_input))

if not requested.startswith(BASE_DIR):
    abort(403)

The broader lesson here is that good recon compounds. The robots.txt from Web 1 didn't solve this challenge directly, but it seeded the right mental model: incident reports, internal directories, something file-related. That pointed toward the right attack surface once the API enumeration surfaced /api/images.