File upload

uploadvulns vulnversity rrootme startup fileuploadattacks nibbles double_extensions mime_type null_byte file_upload_zip local_file_inclusion_wrappers file_upload_polyglot

It's common for websites to allow users to upload files such as an avatar. Unfortunately, in some cases, a hacker can upload malicious files such as a script leading to Remote Code Execution (RCE).

Usually, most websites have filters, but there are often logic flaws in the filtering, leading to malicious files successfully uploaded.

There may be JavaScript filters, and to be more efficient while making requests, we usually use tools such as:

# submit a file with name=file and value=path/to/file
$ curl -X POST -F "submit:value" -F "file:@path/to/file" URL

➑️ Refer to File Upload Wordlists.

Theoretical Process

  1. βœ… Upload a valid file
  2. πŸ” Look for the folder where the file was uploaded.

  • Try to determine the naming scheme (ex: {time}-{filename}.png). You may have to use forced browsing tools if indexing was turned off.
  • Try to see the behavior if uploading a file with the same name

  1. β›” Try to upload a file that may be rejected
  1. πŸ”“ If it was rejected, try a lot of payloads to see what the filter is using to assess whether a file can/can't be accepted. See the filter evasion section below. Test your valid file with:
  • the extension of the one that was rejected
  • the MIME type of the one that was rejected
  • the magic number of the one that was rejected
  • ...
  1. πŸ’£ Try testing different file sizes to find the maximum upload size

Filter evasion

PHP functions that may be involved: pathinfo...

  • ➑️ The filter may uses "contains" instead of "ends with", which is often present due to the usage of a regex while missing a $.
  • ➑️ bypass blacklists/deny list

    • Other extensions that may have been enabled: .php5, .phtml, .php2, .php3, .php4,.php7, .pht, .phps, .phar, .inc...
    • Bypass case-sensitive filters, but Linux servers will not execute them: .pHp, .PHP, .PHTML...Β 

  • ➑️ Try injecting characters

For instance, the null byte (PHP < 5.3.4):


malicious.php%00.png -> malicious.php
malicious.php\x00.png -> malicious.php

Other characters:

  • %20 (space)
  • %0a/%0d%0a/%0d%0d%0a (line breaks)
  • /, .\, ., …,
  • On Windows, file.php:.jpg becomes file.php
  • ➑️ If there is a filter checking for the <?php tag, you can try
    • testing if the filter is case-sensitive: <?PHP, <?pHP...
    • testing with another variant: <?="xxx"?>...

  • ➑️ bypass MIME-type checks by manually editing the Content-Type header of the request. This won't work if the server uses the magic number (mime_content_type, etc.)


Content-Type: application/php -> image/png
  • ➑️ An alternative to editing MIME-type is spoofing the file magic number. Using a command such as file xxx, you can see the type of your file. This is done by checking the first bytes of the file for a value called magic numbers/Apple Reference.
$ echo 'GIF8<content here>' > script.php # ex: fake GIF
# Ex: use JPG magic number (4 bytes: FF D8 FF E0)
$ mv script.php script.jpg
$ file script.jpg # ASCII text
$ cat script.jpg
xxxx[...] # added 4 dummy characters at the start
$ hexeditor script.jpg 
# replace the first four with the magic number
# FF D8 FF E0
$ file script.jpg # JPG

Other techniques

Reverse Double Extension

fileuploadattacks double_extensions

It's possible that the website administrator had misconfigured the web server, allowing files such as script.php.jpg to be executed.

As regexes are used to define which files can be executed, if the $ is missing, then the server is misconfigured.

As this is not common to edit this kind of setting, it's unlikely to occur.

Polyglot File


In some scenarios, the only way to by-pass mitigations is to hide two files in one, with both of them valid. It's not always possible.

Due to how a phar works, it's possible to add an image such as JPG, inside the stub, before the php code.

Side Attacks

fileuploadattacks file_upload_zip

Even if the upload is not vulnerable and we can't upload a webshell, we may still be able to perform other attacks:

  • Use the filename for injections (command, XML, SQL, etc.)
$ file$(whoami).jpg
$ file`whoami`.jpg
$ file.jpg||whoami
  • Use a overly long filename to see if it raises an error

  • If we can upload a SVG, we can try a XXE attack to read the source code (disclose the upload directory, etc.).

  • If the websites display the metadata, we may be able to perform an XSS attack. For instance,

$ exiftool -Comment='<xss payload here>' file.php
  • When uploading a ZIP that is decompressed, you may try to see if you can use symlink to read files.
$ ln -s ../../../index.php index.txt   # read index.php
$ zip --symlinks index.txt
$ zip -y index.txt

Mitigation πŸ›‘οΈ

  • Extension Validation πŸ”’: both blacklist and whitelist extensions. Ensure the logic checks the last extension.

  • Filetype Validation πŸ”‘: do not use the client Content-Type/MIME type. Use the magic number to check the file type.

  • Upload Folder Disclosure πŸ“: hide the upload folder, especially if users are not supposed to access uploaded files. If possible, ensure it is not accessible from the web (see also: web root, .htaccess, etc.).

  • Server-side Validation πŸ“š: client-side validations are nice for normal users but not enough as they can be disabled or ignored.

  • Upload File(s) Disclosure πŸ“„: if the folder is accessible, access to uploaded files must be restricted based on whether should be able to access them or not. Randomize the names or avoid using user-input to name the file (ex: append the extension). Disable indexing.

  • Add Upload Size 🎑 restrictions and use a WAF 🧯

As always, we can configure the server to block some functions or disable access to folders outside the application directories.

πŸ‘» To-do πŸ‘»

Stuff that I found, but never read/used yet.

  • FTP, if it's linked to the website folder, and we can upload files
  • Decompression Bomb, Pixel Flood
  • Windows specific attacks with invalid filename (CON, COM1, LPT1, or NUL) or reserved characters (|, <, >, *, or ?)