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

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:


Once we’ve logged in, we’re presented with the account 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:

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


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



Here Burp Suite will intercept the file upload request:

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:

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:


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:

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




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

With this, we return to our 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:

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


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:


And this way, we complete the lab:

