PortSwigger's "Web shell upload via Content-Type restriction bypass" Walkthrough

This is the next of PortSwigger’s file upload labs. This one is only slightly more difficult because of a Content-Type check being performed by the server.

You’ll need Burp Suite set up before following this walkthrough. You’ll also need a Portswigger Academy account. Once logged into your account, view the lab at https://portswigger.net/web-security/file-upload/lab-file-upload-web-shell-upload-via-content-type-restriction-bypass. This is accessible from the “all labs” view or from the File Upload page.

Challenge Information

Click the “Access the Lab” button and you will be taken to a temporary website that is created for your account. This will be in format https://<random string here>.web-security-academy.net/.

As before, we’ll to upload a PHP script as our avatar. This PHP code will execute once visited in a browser, allowing us to exfiltrate the contents of /home/carlos/secret.

Here’s the website:

If we login with provided credentials wiener:peter, we can upload avatar photos via the /my-account view:

Lab Solution

Open a text editor and save the following contents in a file named webshell.php:

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

Then try to upload the file:

It says that we’re restricted to two allowed Content-Types. These are image/jpeg and image/png. We uploaded one that’s text/php.

In Burp Suite, find the request in Proxy > HTTP proxy, right-click it, and then Send to Repeater.

The request defines the Content-Types in the form data. We can change the value for our web shell to image/jpeg.

Click send, and see that it was successful.

In your browser, reload the /my-account page and then right-click the broken avatar image (broken because it’s not a real image file), and open in a new tab:

This new tab is the PHP file we uploaded, which will execute to get the file contents and then echo them as output.

Take this value (GCHjG786pKA2IND9uMO3M4grtctSChaB) and submit it:

The lab is now solved!