Skip to content
Field Detail
Platform PortSwigger Web Security Academy
Type File Upload Vulnerabilities
Difficulty Practitioner
Objective Escape the upload directory via path traversal in the filename to place a PHP web shell in an executable location, then read /home/carlos/secret

Web Shell Upload via Path Traversal

I uploaded tetoshell.php directly — no Content-Type checks, upload succeeded.

Screenshot

Requesting it:

Screenshot

PHP source returned as plain text — the server doesn't interpret PHP in /files/avatars/. The upload path is intentionally neutered. The shell can live there but can't run there. When a shell uploads but doesn't execute, think directory, not extension: the file was there, the PHP was valid, but the interpreter was disabled for that path.

I intercepted the upload and modified the filename parameter in Content-Disposition:

Content-Disposition: form-data; name="avatar"; filename="../tetoshell.php"
Screenshot

The response still showed avatars/tetoshell.php — the server sanitized the literal ../. Checking /files/tetoshell.php returned 404. The traversal was caught.

URL-encoding the slash:

Content-Disposition: form-data; name="avatar"; filename="..%2ftetoshell.php"

The server either doesn't decode %2f before its sanitization check, or decodes it after — a classic inconsistency. It stripped ../ but ..%2f passed through, letting the filesystem handle the traversal. The file landed in /files/ instead of /files/avatars/.

/files/tetoshell.php?cmd=whoami returned carlos. The parent directory executes PHP. The Content-Disposition filename is always user-controlled — any server that stores files using the client-provided filename without stripping path separators is vulnerable. The fix is to extract just the basename and discard everything before the last / or \.

Reading the secret:

/files/tetoshell.php?cmd=cat /home/carlos/secret
Screenshot

Submitting:

Screenshot

Lab solved :P

Resources