File Upload Attacks

PRACTICE ! PRACTICE ! PRACTICE !

Remote code exec via web shell upload

Upload an image and proxy it through burpsuite, Note if the image's preview is shown on the page. Go to the HTTP history, under MIME type checkbox images so that it will show all the images returned in the history tab.

Notice that the image which we uploaded was fetched by a GET request, send that request to repeater. Meanwhile, create a exploit.php file which will basically fetch the contents of the target file.

Now upload this exploit.php file, and it returns a status code 200 which means our file was uploaded successfully uploaded. Now how do we access our exploit.php ?

Simply, go the repeater tab and tamper the header by inserting our exploit.php and send the request and the target's content will be displayed in the response tab.

Obfuscating file extensions

1

To bypass .php, we'll have to use lesser known extensions which resemble the same such as

  1. .php5

  2. .shtml

  3. .pHp

2

For a medium level secured application, we must try tampering the extensions from .php to .jpg | .jpeg | .png and upload it.

Keep your burp ready, intercept the request and change it to .php and forward the request, your backdoor will be uploaded.

Interact with your backdoor by triggering it in the location where it is uploaded in the web page.

3

For an advanced level secured application, repeat the same but while modifying it in the burp proxy add .jpeg to it in the end. Example => filename: shell.php.jpeg

We can even try by URL encoding the dots => exploit%2Ephp.

URL-encoded null byte characters before the file extension. If validation is written in a high-level language like PHP or Java, but the server processes the file using lower-level functions in C/C++, for example, this can cause discrepancies in what is treated as the end of the filename: exploit.asp;.jpg or exploit.asp%00.jpg or exploit.php#.jpg

Web shell upload via path traversal

Asusual upload an image and proxy it through burpsuite, observe the image which we uploaded was fetched by a GET request. Send that request to the repeater tab. Meanwhile create a exploit.php file which fetches the target's contents.

Now when we try to upload the exploit.php file, it'll not restrict us from uploading the file. So now it's easy we got a RCE, our exploit.php file is uploaded and now we can trigger it by changing the GET request in the repeater tab.

But when we do that, we notice our exploit.php code is returned as plain text in the response tab, Why is this happening ?

Let's investigate it using our POST form {exploit.php's}, Everything is set so it should work fine but it's not. So if we take a closer look at the Content-Dispostion header, our filename is exploit.php, when we try to tamper the file name to a directory-traversal sequence : Content-Disposition: form-data; name="avatar"; filename="../exploit.php

Now sending this request we recieve a response saying the file has been uploaded, which suggests that the server is stripping the directory traversal sequence from the filename.

Now a bit more advanced way is to encode characters in our payload that is, instead of / we can use %2f. Now if we send the request, we can notice the response /files/avatars/../exploit.php has been uploaded, which means the server decoded our %2f.

Now that we know our payload worked and there is a directory traversal method to access the target's content, let's trigger but before doing that. Observe the GET request of our %2fexploit.php in the HTTP history.

So what is happening in the backend ? This indicates that the file was uploaded to a higher directory in the filesystem hierarchy (/files), and subsequently executed by the server. Note that this means you can also request this file using GET /files/exploit.php.

Web shell via Content-Type restriction bypass

Modern server config => compares it with a pre-configured mapping between extensions and MIME type.

NOTE ==> Burpsuite's Content-Type response header may provide some clues.

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

While submitting HTML forms, the request goes and hits the server in a POST form with the Content-Type : application/x-www-form-url-encoded.

The same way while submitting or uploading an image, the request goes and hit the server in a POST form with the Content-Type : image/jpeg. So, it's very much important to observe the Content-Type, while intercepting the requests.

Upload an image and proxy it through burpsuite, Notice the image was fetched using a GET request. Send it to the repeater, Meanwhile upload the exploit.php file which will return our target's contents.

But here when we try to upload our .php file, the response indicates that we aren't allowed to upload the file and hence the server is configured to the MIME type image/jpeg or image/png. So whenever we encounter an error where it says us to not upload some particular file, it's something wrong with the Content-Type.

To investigate that, we'll have to go to the HTTP history and find the POST request which has our exploit.php because our uploaded image or file will go and hit the server in a POST form. Send it to the repeater tab.

In the repeater tab, change the specified Content-Type to image/jpeg. Send the request and observe our exploit.php was uploaded successfully, we just tampered the Content-type according to the MIME type which was configured by the server.

Now that we know our exploit.php has been uploaded, to retrieve the contents of the target. Switch to the other repeater tab {which was GET request}, and tamper the header by inserting our exploit.php.

Over-riding Apache's Configuration

For an example, before an apache server will execute PHP files requested by a client. Dev's should add the following directives to thier /etc/apache2/apache2.conf file.

LoadModule php_module /usr/lib/apache2/modules/libphp.so AddType application/x-httpd-php .php

Apache servers generally have .htaccess file, which will load directory-specific configurations.

Even when our file extension is blacklisted, we can still manage to bypass the server by mapping an arbitrary custom file extension to an executable MIME type.

Upload an image and proxy it through burpsuite, notice our image was fetched using a GET request. Send it to the repeater tab.

Meanwhile create exploit.php which extracts the contents of the target, upload that as your image and we'll get an error saying we can't upload .php files onto the server.

Let's investigate it using our POST form in the HTTP history, In the response we can observe the headers revealing it's an apache server. Send it to the repeater tab.

Modifying the POST form : filename parameter to .htaccess Content-Type header to text/plain Our php payload to AddType application/x-httpd-php .133t

.133t is an arbitrary extension to the executable MIME type application/x-httpd-php. As the server uses the mod_php module, it knows how to handle this.

Send the request and we get a 200 status code, Going back to our .php exploit which din't work. Change the value of the filename parameter from exploit.php to exploit.133t, Send the request and we get a response saying it has been uploaded.

The final step is to trigger our .php exploit, which can be done by changing our image's filename into exploit.133t. Thanks to the .htaccess file, the .133t file was executed as if it was a .php file.

Exiftool - Polygot shell

Nowadays modern servers doesn't check for the extensions and the Content-Type specified in the request.

In the case of image upload functionality, the server may check certain intrinsic properties of an image such as dimensions, where our exploit.php is just a file and files don't have any dimensions.

So now do we have to insert our payload inside an image ? How do we do that ?

This can be achieved by using the exiftool.

exiftool -Comment="<?php echo 'START ' . <PAYLOAD> . ' END'; ?>" jason.jpg -o polyglot.php

Upload the polygot file, and backend approves our php file. Now tamper the GET request and we'll trigger our payload

Last updated