In this post, we’ll be solving the PortSwigger lab: “Web shell upload via Content-Type restriction bypass”.

PortSwigger lab home page

To solve the lab, we need to upload a PHP file that reads and displays the contents of the /home/carlos/secret file. Since to demonstrate that we’ve completed the lab, we must submit the contents of this file.

Additionally, the server is configured to prevent file uploads based on the Content-Type. So we’ll need to bypass this defense.

In this case, the lab itself provides us with an account to log in, so let’s do that:

Login form

Provided access credentials

Once we’ve logged in, we’re presented with the account profile:

User profile

As we can see, we have an option to upload a file, specifically it appears to be for updating the profile avatar. Let’s try to take advantage of this option to upload the following PHP file:

PHP code to read the secret file

First, let’s prepare Burp Suite to intercept the request:

Browser proxy configuration

Activating interception in Burp Suite

Once we have Burp Suite ready along with the proxy, we select the file and click “Upload”:

File selection for upload

File upload confirmation

Processing file upload

Here Burp Suite will intercept the file upload request:

Intercepted request in Burp Suite

Let’s send the request to the repeater for better handling, to do this, we press Ctrl R.

Once in the repeater, when we click “Send”, we can see the server’s response to the file upload:

Server response showing restriction

In this case, it indicates that files whose Content-Type header is application/x-php are not allowed. And that only those with image/jpeg or image/png are permitted.

Knowing the type of restriction the server is imposing on us, we can simply change the Content-Type of our request:

Modifying the Content-Type in the request

Content-Type modified to image/jpeg

With this, the file content doesn’t change, and it won’t affect its interpretation either. With this change, we try uploading the file again:

Successful server response

This time we see that it has been successfully uploaded. We can view this response in the browser as follows:

Show response in browser option

URL to display response in browser

Viewing the response in the browser

Accessing the profile from the browser

Once we get here, we can now disable Burp Suite, as we won’t be using it anymore.

Proxy deactivation

With this, we return to our profile.

Accessing user profile

Now, if we look at the profile, we can see that the avatar has changed and is now showing an error that the image isn’t loading properly:

Avatar with loading error

By right-clicking on it, we can go directly to the image path to see if it’s our PHP file:

Context menu to open image

Successful PHP file execution

Indeed, the PHP file we uploaded has been stored as the avatar file, that’s why it wasn’t loading on the profile, it was trying to load an image when it wasn’t one. By visiting the PHP file, the code we placed has been interpreted, and we successfully read the secret file.

Having read this file, we simply submit the answer:

Form to submit the solution

Submitted solution confirmation

And this way, we complete the lab:

Lab completed successfully

Final confirmation message