Overview
Uploaded files represent a significant risk to web applications. The first step in many attacks is to get malicious code onto the target system. Using a file upload vulnerability helps attackers accomplish this goal. The consequences of unrestricted file upload include:- Complete system takeover via remote code execution
- Overloaded file systems leading to denial of service
- Defacement by overwriting web content
- Backend system attacks by forwarding malicious files
- Data exfiltration through uploaded web shells
Objective
Execute arbitrary PHP functions (such asphpinfo() or system()) on the target system by exploiting file upload vulnerabilities.
Vulnerability Analysis by Security Level
Low Security
Vulnerability: No file type or content validation whatsoever. Source Code (/vulnerabilities/upload/source/low.php:1-19):
-
Upload via form:
- Select
shell.phpin file upload form - Click “Upload”
- Note the success message with file path
- Select
- Access uploaded shell:
- Execute commands:
Medium Security
Mitigation Attempt: Client-side MIME type validation Source Code (/vulnerabilities/upload/source/medium.php:1-33):
- Modify Content-Type to:
- Extension whitelist (
.jpg,.jpeg,.png) - Size limit (< 100KB)
getimagesize()validation
getimagesize()only checks file headers, not content- PHP code can be embedded in image metadata
- Doesn’t strip dangerous content
- Create valid JPEG with PHP payload:
- Anti-CSRF Token: Prevents automated upload attacks
- Extension Whitelist: Only
.jpg,.jpeg,.pngallowed - MIME Type Validation: Checks both client and server-determined types
- Image Verification: Uses
getimagesize() - Re-encoding: Critical - completely re-creates image, stripping all metadata and embedded code
- Filename Randomization: Uses
md5(uniqid())to prevent predictable names - Temporary Processing: Works in temp directory before moving to final location
- Size Limits: Enforces 100KB maximum
2. Validate MIME Type (Server-Side)
4. Randomize Filenames
6. Disable Script Execution in Upload Directory
Apache (.htaccess):7. Complete Validation Function
Bypassing getimagesize()
Create polyglot JPEG/PHP:Key Takeaways
- Never trust client input: MIME types and extensions can be spoofed
- Validate server-side: Use
finfo_file()andgetimagesize() - Re-encode images: This is the only way to truly strip malicious content
- Randomize filenames: Prevents predictable file paths
- Store outside webroot: Or disable script execution in upload directory
- Defense in depth: Combine multiple validation layers
- Consider file inclusion: Upload + LFI = RCE even with image validation
