A web application allowing file upload takes on the risk of allowing end-users to store their potentially malicious data on the web application’s back-end server. If the user input and uploaded files are not properly filtered and validated, attackers may be able to exploit the file upload feature to perform malicious activities.

Unauthenticated arbitrary file upload is when a web application allows any unauthenticated user to upload any file type. The most common attack causes by arbitrary file upload is gaining remote command execution over the back-end server.

Absent Validation

The most basic type of this attack is when the web application does not have any form of validation filters.

Our uploaded web shell has to be written in the same programming language as the web server, as it runs platform-specific functions and commands. Web Routes will usually map URLs to web pages, in which web page extension may not be shown. The most common way to determine what language runs the web application is by visiting /index.ext where ext is the common web extensions.

Wappalyzer can also be a useful tool to identify programming language.

We can test the vulnerability by writing a simple Hello World! script. Here is an example in PHP

<?php echo "Hello HTB";?>

Note: writing echo will display the result of the command or whatever follows it.

Client-Side Validation

Many web applications rely on front-end Javascript to validate the selected file format before it is uploaded. Since it is client-side it can be disabled.

Within a network request we may modify the file we are uploading to bypass the validation

We can modify the filename="HTB.png" and the file content to successfully upload our webshell.

We can also modify the Content-Type of the uploaded file.

We may also manipulate the front-end code. A typical front-end validation code will look something like

<input type="file" name="uploadFile" id="uploadFile" onchange="checkFile(this)" accept=".jpg,.jpeg,.png">

accept=... is responsible for which files we can select in the file selection dialog. We also notice the call to checkFile() which itself has

function checkFile(File) {
...SNIP...
    if (extension !== 'jpg' && extension !== 'jpeg' && extension !== 'png') {
        $('#error_message').text("Only images are allowed!");
        File.form.reset();
        $("#submit").attr("disabled", true);
    ...SNIP...
    }
}

Blacklist Filters

If we get Extension not allowed or similar this indicates that the web application may have some form of file type validation on the back-end. Two types of validation can be put in place

  • Blacklist of types - weakest type because the lists it compares against is usually not comprehensive and does not account for case-insensentivity.
  • Whitelist of types The validation may also check the file type or the file content for type matching.

We may fuzz for what extensions are being validated via Burp Intruder (turn off URL encoding to make sure the . doesn’t change) and a Web extension wordlist.

Whitelist Filters

Validates by utilizing a list of allowed extensions. Typically more secure than a blacklist.

A simple bypass of for example a regex test is through Double Extensions. If the .jpg is validated we can use the shell.php.jpg file and it will work.

Some web server configurations allow any files if the PHP extensions to be executed and does not check if it ends with the PHP extension.

We may also use Character Injection to cause the web application to misinterpret the filename and execute the uploaded file as a PHP script. Characters include

  • %20
  • %0a
  • %00
  • %0d0a
  • /
  • .\
  • .
  • …
  • :

Type Filters

Modern web servers and applications test the content of the uploaded file to ensure it matches the specified type. Content filters specify a single category (images, videos, documents, etc.)

The Content-Type header is included in our web request and the browser is usually the one that set this. The operation is a client-side operation. We may fuzz this via the web-all-contents-types.txt wordlist.

A HTTP request has two Content-Type headers, one for the attached file and one for the full request. If the uploaded content was as POST data we will need to modify the main Conten-Type header.

The more common file content validation is testing the uploaded file’s MIME-Type. Multipurpose Internet Mail Extensions (MIME) is an internet standard that determines the type of a file through its general format.

This is usually done by inspecting the first few bytes of the file’s content, which contain the File Signature or Magic Bytes.

Many other images types have non-printable bytes for their file signatures. GIF87a or GIF89a is the easiest one to use since it is ASCII-printable.

Limited File Uploads

File types allow us to introduce a Stored XSS vulnerability by uploading maliciously crafted version of them.

The most basic example would be if web applications allowed to upload HTML files.

Another example would be a website that displays image metadata. We can inject XSS into the image’s metadata.

XSS attacks can also be carried with SVG images, since they are XML-based and they describe 2D vector graphics. Such a payload would look like

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="1" height="1">
    <rect x="1" y="1" width="1" height="1" fill="green" stroke="black" />
    <script type="text/javascript">alert(window.origin);</script>
</svg>

xss

Similar attacks can lead to XXE exploitation. SVG images can include malicious XML data to leak the source code of the web application.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<svg>&xxe;</svg>

Through this, we can locate the upload directory, identify allowed extensions, and find the file naming scheme through source code leak.

To leak PHP source code we could use a payload such as

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php"> ]>
<svg>&xxe;</svg>

Such an attack is not unique to XML files, other file types such as PDF, Word Documents, Powerpoint Documents, etc. are vulnerable.

xxe

We can utilize a decompression bomb with file types that use data compression, if a web application automatically unzips the archive, this can lead to petabytes of data being unloaded and crash the server.

Another DoS is a Pixel Flood attack with some images that utilize compression, like JPG or PNG. We can create any image file with any image size and then manually modify the its compression data to say it has a size of 0xfffff which is 4 Gigapixels.

Some file uploads may not have a limit of the upload size.

We may also attempt to upload files to a different directory which might cause the server to crash.

File Name

We can also upload a malicious string for the uploaded file name, which may get executed or processed if the upload file name is displayed/reflected on the page. Some examples include file$(whoami).jpg or file`whoami`.jpg or file.jpg||whoami. We could as well use XSS payload in the file name xss.

Directory Disclosure

We may not have access to the link of our uploaded file and may not know the uploads directory. We may utilize fuzzing to look for the uploads directory or even use other vulnerabilities to find where the uploaded files are by reading the web apps source code.

We can also force the web app to display errors. For instance, creating a file that already exists, or sending two identical requests simultaneously. We could also try uploading a file with overlong name.

Windows

Using reserved characters like |, <, >, *, or ? which are usually reserved for special uses like wildcards, if the web application does not properly sanitize these names or wraps them within quotes. We can also use reserved names like CON, COM1, LPT1, or NUL.

We can also use the Windows 8.3 Filename Convention to overwrite existing files, by using the ~ character to complete the file name. For example, to refer to a file called (hackthebox.txt) we can use (HAC~1.TXT) or (HAC~2.TXT), where the digit represents the order of the matching files that start with (HAC).