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 ourexploit.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
.php5
.shtml
.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 isexploit.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 thefilename
.
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 usingGET /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 typeimage/jpeg
orimage/png
. So whenever we encounter an error where it says us to not upload some particular file, it's something wrong with theContent-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
toimage/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 ourexploit.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 totext/plain
Ourphp
payload toAddType application/x-httpd-php .133t
.133t
is an arbitrary extension to the executable MIME typeapplication/x-httpd-php
. As the server uses themod_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 fromexploit.php
toexploit.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 ourimage's
filename intoexploit.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
.
Upload the polygot file, and backend approves our php
file. Now tamper the GET request and we'll trigger our payload
Last updated