Skip to content
Field Detail
Platform PortSwigger Web Security Academy
Type File Upload Vulnerabilities
Difficulty Practitioner
Objective Bypass extension validation using a null byte injection in the filename to upload a PHP web shell and read /home/carlos/secret

Web Shell Upload via Obfuscated File Extension

Uploading tetoshell.php was rejected:

Sorry, only JPG & PNG files are allowed
Screenshot

The server validates the extension against an allowlist — previous techniques don't apply. The challenge is satisfying the .jpg or .png check while still having the file stored and executed as PHP.

The null byte (\x00, %00 URL-encoded) is the string terminator in C, and languages that call into C libraries for string operations inherit the same behavior. If validation runs in a higher-level language and reads tetoshell.php%00.jpg as a filename ending in .jpg — allowlist passes — but the underlying filesystem call terminates at the null byte and stores the file as tetoshell.php, the validator and the filesystem see different strings. Modern PHP strips null bytes from filenames automatically (since 5.3.4), but legacy apps, some Java frameworks, and custom C/C++ file-handling code can still be vulnerable.

I intercepted the upload and modified the filename:

Content-Disposition: form-data; name="avatar"; filename="tetoshell.php%00.jpg"
Screenshot
The file avatars/tetoshell.php has been uploaded.

The server's own response confirmed what got stored — tetoshell.php, not .jpg. The .jpg suffix was dropped at the null byte, confirming the injection worked before even attempting execution.

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

Lab solved :P

Resources