Skip to main content
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 page, you can find more about webshells and payload generation.
$_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.

Extension Filter Bypasses

Most filters block .php but miss the full set of extensions a given web server will still happily execute as PHP.
SecLists’ PHP extension list covers this exhaustively, worth fuzzing the full set against the target rather than guessing one at a time.
On case-insensitive filesystems (Windows) or a filter doing an exact-match blacklist, changing the case still resolves to the same handler.
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).
Which one works depends entirely on how the target parses the filename, try both directions since server configs vary.
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.
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.
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.
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.
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.

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..
SecLists’ full content-type list is worth narrowing down before fuzzing. A quick one-liner to filter grep all image types:

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.
Full 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.
Check if the payload was injected.

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 in SVG`s also supports external entities, turning an upload into an XXE vector for local file read. See XEE (XML External Entitiy) for various techniques.
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 for more on PHP wrappers).

Quick Reference Tools

Hackviser: File Upload

Reference used for this page.

HackTricks: File Upload

Deeper dive into additional bypasses and edge cases.

List of File Signatures

Full magic byte reference for any format.

SecLists: Web Extensions

General web extension wordlist.

PayloadsAllTheThings: PHP Extensions

Exhaustive PHP-executable extension list.

fuxploider

Automated file upload vulnerability scanning and exploitation.