Every section required answering a slightly different question: can I overwrite an existing file? Can I upload executable code? Where does the file land? Is it served or executed? What filter is actually blocking me? What backend is processing the file?


1. Basic Webshell Upload

Gobuster identified the upload location. Uploaded a tiny PHP webshell:

<?php echo system($_GET["cmd"]); ?>

The uploaded shell was reachable and executable. whoami returned www-data. Flag retrieved from /var/www/flag.txt.

The file wasn't just stored — it was being interpreted server-side as executable PHP. That distinction matters.


2. Client-Side Filter Bypass

Page source referenced client-side-filter.js — a JavaScript file enforcing image upload restrictions in the browser. Browser-side validation is not validation.

The PHP webshell was renamed to shell.png to pass the file picker. Then in Burp:

  • filename changed from shell.png to shell.php
  • content type changed from image/png to text/x-php

Upload succeeded. Shell executed from /images/shell.php.

Burp intercepting multipart POST with filename and content-type modified Upload success redirect after Burp modification Webshell executing as www-data Flag retrieved via webshell command execution

3. Extension Blacklist Bypass

Server-side extension blacklist blocked common PHP extensions. The PentestMonkey reverse shell was renamed to php-reverse-shell.jpg.php5 — the blacklist didn't cover .php5, which still executed.

The upload interface used CLI-style commands rather than a standard form. After upload, the file landed in /privacy/ with a randomized timestamp prefix. Triggered it directly. Reverse shell connected back.

CLI upload interface accepting .php5 payload /privacy/ directory listing showing timestamp-prefixed uploaded file

4. Magic Number Bypass

Server-side validation checked the file's magic bytes rather than the extension. Modified the payload in hexeditor to begin with the GIF magic number:

47 49 46 38 39 61  →  GIF89a

The file command confirmed the spoofed type. Upload accepted. Retrieved the flag via the known path using a webshell instead of a reverse shell for simplicity.

hexeditor showing GIF magic bytes prepended to PHP payload file command confirming payload identified as GIF image data Flag retrieved via spoofed upload path

5. Black-Box Node/Express Exploitation — Jewel

The hardest challenge. The upload and execution paths were completely separate, and the backend wasn't PHP.

The upload endpoint response contained X-Powered-By: Express. That was the key clue. A PHP payload was the wrong fit entirely.

Gobuster identified three directories: /admin, /content/, /modules/. Uploaded files landed in /content/ with randomized short filenames. Retrieving them with curl showed the raw payload — they were being served, not executed.

Gobuster identifying /admin, /content/, /modules/ and curl showing raw payload in /content/

The /admin page contained a form that activated modules from /modules/. Intercepting the admin POST in Burp revealed:

POST /admin?submit=failure HTTP/1.1
body: cmd=...

Removing ?submit=failure from the request line and supplying a traversal path to the uploaded file converted a failed module lookup into code execution.

Burp correcting admin POST request line and supplying traversal path to /content/

A JS reverse shell payload wrapped to satisfy JPEG client-side checks was uploaded, the randomized filename identified, and the corrected admin request fired. Root shell connected back.

Root shell via Node/Express upload chain — flag retrieved from /var/www/

What This Room Actually Teaches

The biggest conceptual shifts across all six challenges:

  • Don't trust the upload path to also be the execution path
  • Recognize when the backend invalidates your payload choice
  • Use Burp to correct or reshape requests, not just bypass browser restrictions
  • Treat small enumeration details as execution clues rather than noise

The Jewel challenge especially reinforced that the right answer is often not "try more payloads" but "better understand how the application routes uploaded content."