portswigger-all-labs

Complete PortSwigger Web Security Academy Lab Writeups Detailed, categorized solutions for every lab — from APPRENTICE to EXPERT — covering all 30 vulnerability types.

View on GitHub

Labs Covered

This write-up focuses on the following PRACTITIONER-level labs from the PortSwigger Web Security Academy:

3 Web shell upload via path traversal

This lab demonstrates how attackers can abuse directory traversal vulnerabilities during file upload to place web shells into executable directories, resulting in remote code execution.

4 Web shell upload via extension blacklist bypass

This lab shows how attackers can bypass file extension blacklists by manipulating filenames to evade validation checks, enabling successful web shell uploads.

5 Web shell upload via obfuscated file extension

This lab demonstrates how attackers can craft filenames with obfuscated extensions (using techniques such as Unicode characters, null bytes, or multiple extensions) to bypass file validation mechanisms.

6 Remote code execution via polyglot web shell upload

This lab shows how attackers can craft polyglot files that satisfy multiple file type checks simultaneously, allowing them to upload executable files disguised as safe file types and achieve remote code execution.

LAB 3 - Web shell upload via path traversal

Lab Description :

image

Solution :

The default credentials that we have are wiener:peter.We login with that credential

Next, I will upload a malicious file with a .php extension. I have named the malicious file myexploit.php.

In the screenshot below, you can see that I have highlighted two important requests captured in Burp Suite:

  1. The GET request — this reveals the location of the uploaded image on the server.
  2. The POST request — this is responsible for uploading the myexploit.php file to the server.

To proceed with testing and analysis, I will forward both of these requests to the Repeater tab in Burp Suite. This allows me to modify and resend the requests manually to observe the server’s behavior and confirm if the malicious file upload was successful.

image

After sending both requests to the Repeater tab in Burp Suite, I renamed them for better clarity and organization.

The POST request, which is responsible for uploading the malicious file (myexploit.php), was renamed to UploadImage. This request is used to interact with the file upload functionality.

The GET request, which is used to view the location of the uploaded file on the server, was renamed to ShowImage. This helps in easily identifying and man

image

As you can see in the screenshot below, I initially changed the filename to ../exploit.php in an attempt to perform a directory traversal and place the file into the parent directory.

However, simply using ../ may not work, as many web applications sanitize or block forward slashes (/). To bypass this restriction, we need to obfuscate the forward slash by URL encoding it. The encoded value of / is %2f.

Therefore, I modified the filename to ..%2fmyexploit.php. This encoding helps bypass basic filtering and allows us to attempt writing the file in the parent directory, which, in this lab scenario, has executable permissions.

The file I uploaded is named myexploit.php, and it contains the following PHP payload:

<?php echo system($_GET['command']); ?>

image

Now that our file has been successfully uploaded to the previous directory, we can access it by modifying the URL. Originally, uploaded files are served from the /avatar/ directory. However, since we used a path traversal technique (..%2f) during the upload, our file (myexploit.php) was placed in the parent directory of /avatar/.

image

Submit the secret to solve the lab.

image


LAB 4 - Web shell upload via extension blacklist bypass

Lab Description :

image

Overview:

One of the more obvious ways of preventing users from uploading malicious scripts is to blacklist potentially dangerous file extensions like .php. However, the practice of blacklisting is inherently flawed, as it’s difficult to account for every possible variation that could be used to execute code.

Attackers can often bypass these blacklists by using lesser-known or alternative extensions that are still interpreted by the server as executable. Examples of such extensions include:

Because web servers like Apache and Nginx may be configured to treat these extensions the same as .php, relying solely on extension blacklisting is an insecure approach to file upload validation.

Solution :

Login as wiener to access the upload functionality.

Upload a .php file with the following payload <?php phpinfo() ?>.`

image

I have also attempted to bypass the extension blacklist by using a double extension technique, naming the file as phpinfo.jpg.php. This method is commonly used to trick file upload filters that only check the last extension or expect image formats like .jpg or .png.

However, in this case, the server is still blocking the upload, indicating that it is performing more strict validation. It likely checks the entire filename, not just the final extension, and explicitly denies files with any suspicious patterns involving .php.

image

Now, I have successfully uploaded a file with a .phtml extension by exploiting the file upload vulnerability. The server did not block this extension, which is still treated as executable by many PHP interpreters.

image

After uploading the malicious .phtml file, I accessed it through the browser. The PHP payload executed successfully, confirming that code execution was achieved.

Then, I changed the payload to the following:

<?php echo file_get_contents('/home/carlos/secret'); ?>

image

Result

image

I then copied the key and sumbit it, the lab is successfully solved.

image


LAB 5 - Web shell upload via obfuscated file extension

Lab Description :

image

Solution :

Lab Goal
Read the contents of /home/carlos/secret by uploading and executing a malicious PHP file through the avatar upload feature.

Login
Log in with the provided credentials.

PHP payload

1. Malicious PHP Payload

We will use this simple one-liner PHP script to read and display the secret file:

<?php echo file_get_contents('/home/carlos/secret'); ?>

PHP payload

This uses file_get_contents() to read /home/carlos/secret and outputs the result directly.

2. Understand Normal Upload Behavior

Before trying the malicious file, upload a normal image to understand how the server handles files.

  1. Go to My account → Upload any real image (e.g. a screenshot)
  2. Observe the success message

Uploading a normal image

In Burp Suite:

HTTP history filter - show images

Successful upload:

Image uploaded successfully

POST request to avatar endpoint in Repeater

Uploaded image displayed on profile

Now we know:

3. Attempt to Upload Malicious File

Try uploading our exploit.php file directly → blocked.

Trying to upload .php file - blocked

4. Bypassing the Filter

Failed Attempts

Double extension attempt - failed

%20 attempt - failed

Successful Bypass: Null Byte Injection

Change the filename in the POST request to:

filename="exploit.php%00.jpg"

Successful upload with null byte

Why it works

Technique What server validation sees What filesystem sees Result
exploit.php ends with .php exploit.php Blocked
exploit.php.jpg ends with .jpg exploit.php.jpg Blocked
exploit.php%00.jpg ends with .jpg exploit.php (stops at \0) Allowed & executable

5. Execute the Webshell

Use the same GET /files/avatars/... request pattern from earlier.

Change the filename to:

GET /files/avatars/exploit.php HTTP/1.1

Send the request → you should see the contents of /home/carlos/secret in the response.

Executing the PHP file via GET request

Secret file contents revealed

Copy the secret key.

6. Solve the Lab

Paste the key into the solution submission box → lab solved!

Lab solved confirmation


LAB 6 - Remote code execution via polyglot web shell upload

Lab Description :

image

Solution :

In this lab, we are exploiting a Remote Code Execution (RCE) vulnerability through an insecure file upload function. Despite any basic protections in place, we are still able to upload files and execute our code on the server-side. The main objective is to upload a PHP web shell and access the /home/carlos/secret file in order to obtain the key and solve the lab.


Step 1: Upload a Basic PHP File

To begin testing the server’s behavior, we first upload a simple PHP file named phpinfo.php with the following content:

<?
php phpinfo();
?>

To bypass this, I changed the filename from phpinfo.php to phpinfo.jpg in an attempt to trick the file extension filter. However, this approach also failed, indicating that the server is performing additional validation checks — possibly analyzing the file content (MIME type) or blocking known file signature patterns associated with PHP.

This confirms that basic extension spoofing alone is not sufficient to bypass the upload restrictions in this scenario.

image

Now, go to Google and search for “magic number image search.” copy jpeg but failed to upload jpeg

image

Next, search for GIF on the wiki website and copy its magic characters.

image

As you can see, the server accepted the GIF magic bytes, allowing us to bypass its file upload security mechanisms. By placing the correct magic number at the beginning of the file (i.e., GIF89a), we made the server believe that the uploaded file was a legitimate image, even though it contained embedded PHP code.

image

To exploit this, I crafted a file starting with the GIF header, followed by the PHP payload:

GIF89a
<?php echo file_get_contents('/home/carlos/secret'); ?>

image

Result:

image

💡 Note: We can also use exiftool to embed our PHP payload into an image file as a comment, creating a polyglot file — one that appears to be a valid image but is also executable PHP code.

To do this, we use the following command:

exiftool -Comment="<?php echo 'START ' . file_get_contents('/home/carlos/secret') . ' END'; ?>" <YOUR-INPUT-IMAGE>.png -o polyglot.php

Submit the key to solve the lab.

image