Contents

File Upload Vulnerability

This article includes the concept of file upload vulnerablity, with its precaution and bypass. There may be more than one updates of this article since there are new methodologies about prevention and exploitation coming up.

A file upload vulnerability refers to a security flaw present in an application or website that allows attackers to perform malicious actions by uploading malicious files. Such vulnerabilities typically occur in functionalities that require users to upload files, such as image uploads, document uploads, attachments, etc. Attackers can exploit this type of vulnerability by uploading files containing malicious code, scripts, or malware, and then executing these files to compromise the security of the system.

File upload vulnerabilities may lead to the following issues:

  • Remote Code Execution: Attackers can upload files containing malicious code and then execute this code on the affected server to perform arbitrary operations, thereby gaining complete control over the server.
  • File Overwrite: Attackers upload files with the same name as existing files, overwriting legitimate files. This may result in loss of functionality, data loss, or users being denied access to files they should be able to access.
  • File Inclusion: Attackers upload files and attempt to include them in other parts of the application, causing the application to perform unexpected actions or disclose sensitive information.
  • Server Denial of Service (DoS): Attackers may upload large files that deplete server resources, rendering the server unable to process other requests.
  • Malicious File Propagation: Attackers can upload files containing malicious software, viruses, spyware, etc., using these files to spread malicious software.

Validate the type, size, and content of uploaded files to ensure that only allowed file types and sizes are accepted.

Here’s a Python example of an input validation strategy. The function takes a filename and attempts to retrieve the file’s extension. It returns a truth value when a . is present in the filename and the lowercase extension is within ALLOWED_EXTENSIONS.

ALLOWED_EXTENSIONS = ['jpg', 'png']

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

In Python, you can use os.path.getsize() to detect the size of a file.

import os

def get_file_size(file_path):
    try:
        size = os.path.getsize(file_path)
        return size
    except OSError:
        return None

Store uploaded files in a separate directory with restricted access to prevent execution of malicious files.

  • Create a dedicated directory on the server for storing uploaded files, isolating it from other parts of the application.
  • Ensure that uploaded files do not have execute permissions to prevent attackers from attempting to execute malicious executable files.
  • Generate a unique filename for each uploaded file to avoid filename conflicts and overwriting.

Here’s a Django example of isolating uploaded files.

from rest_framework.parsers import FileUploadParser
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status

# Set an isolated folder as the upload folder
UPLOAD_FOLDER = 'uploads/'

class FileUploadView(APIView):
    parser_classes = (FileUploadParser,)

    def post(self, request):
        file = request.data['file']
        if file:
            with open(UPLOAD_FOLDER + file.name, 'wb') as dest:
                for chunk in file.chunks():
                    dest.write(chunk)
            return Response(status=status.HTTP_201_CREATED)
        else:
            return Response(status=status.HTTP_400_BAD_REQUEST)

On Linux, you can use chmod to remove the execute and read/write permissions of files in a directory.

Assign randomly generated names to uploaded files to prevent attackers from overwriting legitimate files or accessing webshells by predicting filenames.

As an example using Python’s random.choice(), generate a random string.

import random
import string

def random_string(length):
    letters = string.ascii_letters + string.digits
    return ''.join(random.choice(letters) for _ in range(length))

Scan uploaded files to detect the presence of malicious code.

ClamAV is a commonly used open-source antivirus scanning engine used to detect malicious code and viruses. When dealing with executing external commands, handling processes, etc., using subprocess is a common and recommended practice, as it provides a convenient interface for interacting with system processes, facilitating error handling, and ensuring a certain level of security.

Use the subprocess.run() function to start a new subprocess, executing specific external commands or programs. Communicate with subprocesses via channels such as standard input (stdin), standard output (stdout), and standard error (stderr).

import subprocess

def scan_file_with_clamav(file_path):
    try:
        result = subprocess.run(['clamscan', '--stdout', '-i', file_path], stdout=subprocess.PIPE)
        output = result.stdout.decode('utf-8')
        if "OK" in output:
            return True
        elif "FOUND" in output:
            return False
        else:
            return None
    except Exception as e:
        return None

Certain conditions need to be met for a file upload vulnerability to be exploitable. The uploaded file must be interpreted and executed by the web container, and the directory where the file is uploaded must be within the web container’s covered path. Users must be able to access the uploaded file via the web; if they can’t, or if the web container can’t interpret scripts, the attack might fail.

There are generally two ways for server-side validation of file types:

  • Directly reading the file extension.
  • Parsing the file header information.

Construct a fuzzy directory traversal sequence to upload a file to the parent folder.

filename="..%2fexploit.php"

Use Burp Suite to modify the Content-Type field value. For example, change the MIME type of a file in a POST request body to Content-Type: image/jpeg.

Common MIME types:

text/plain
text/html
text/javascript
application/xhtml+xml
image/gif
image/jpeg
image/png
video/mpeg
application/octet-stream
application/pdf
application/(programming language) (code in that language)
application/msword
message/rfc822
multipart/alternative
application/x-www-form-urlencoded
multipart/form-data

When a Web Application Firewall (WAF) only checks for a Trojan horse in specific file types (e.g., .php or .jsp), this method can be used.

  1. Upload a TXT file named shell.txt containing Trojan content. Due to the file type, the server-side won’t check it.
  2. Upload a PHP file with content <?php include(".shell.txt");?>. Visiting this PHP file will reference the Trojan.
  • Change .php to .php5.
  • Change .html to .shtml.

This can bypass less strict blacklist filtering.

.htaccess is a configuration file for the Apache Web server. It allows site administrators to define rules and settings in the root or specific directories to control website behavior and access permissions. These rules can include redirects, authentication, access control, cache settings, etc.

  • SetHandler directive assigns a handler to specific file extensions or types, enforcing a specific method of handling for matched files.

    SetHandler handler-name
    
  • AddType directive associates a media type (MIME type) with specific file extensions, allowing browsers to correctly display or process files.

    AddType media-type extension
    
  • php_flag sets PHP engine configuration options. Setting the engine value to off or 0 can disable PHP parsing in the current directory and its subdirectories, potentially leading to source code exposure.

    php_flag engine 0
    
  • Concatenate multiple extensions: shell.php.php.

  • Append characters: shell.php..

  • Append a space: shell.php .

  • URL-encode the . character: shell%2Ephp.

  • Null byte bypass: shell.asp%00.jpg.

    Null Byte

    A null byte is used as a string terminator in some programming languages and operating systems, which could cause certain handling functions to incorrectly truncate strings, leading to security vulnerabilities. When an attacker inserts %00 into a filename, the server might mistakenly truncate the filename, causing the uploaded file type and location to differ from expectations, potentially bypassing certain security checks.

  • Semicolon bypass: shell.asp;.jpg.

    In some applications, semicolons might be used as separators between parameters or parameter values, such as in URL parameters or certain scripts. Attackers might attempt to insert semicolons in inputs to separate multiple parameters or values, disrupting the application’s parsing logic.

  • Use multi-byte Unicode characters.

  • Double-write bypass: shell.p.phphp.

    In this payload, .php might be filtered, leaving just shell.php.