I'm trying to understand how null byte injection attacks in PHP code used to work before it was patched in PHP 5.3.4. I have this sample HTML page that is a somewhat modified version of what's shown here:

echo '<br>';
$file = $_GET['file'];
$path = '/var/www/' . $file . '.php';
echo $path;
if (file_exists($path)) {
    echo "file exists!";
    include $path;

This code is running on an Ubuntu 12.04 system running PHP 5.2.17. I would expect a URL like http://localhost/?file=../../../etc/passwd%00 to work, but instead I see \0 printed literally in the string:

array(1) { ["file"]=> string(21) "../../../etc/passwd\0" }

What am I doing wrong? How can I get null byte injection attacks working on my local machine?

  • While I haven't went back to test this, I read later on that the magic_quotes_gpc escapes the null byte. Maybe this was enabled?
    – gsgx
    Commented Oct 8, 2015 at 4:04

1 Answer 1


The echo output with the \0 included is supposed to happen, nothing to worry. In order to understand the attack, you have to know how C and PHP store strings.


In C, a string is simply a a pointer to a memory address where the pointer points to the start of the string, and the \0 character indicates the end. No length is stored, all code that reads strings reads until the \0 character is reached. A C string can be as long as it wants to be.


In PHP, a string consists of two parts: one integer and one array. The integer denotes the length of the string and the array, the array contains the string itself. All String handling code in PHP reads that integer and knows how long the string is. It ignores the \0 character. The integer has an upper limit, and so does the length of the string.

The attack

The attack bases on this different string handling. So as you can include a \0 character into the PHP string, printing the string will include the \0 character. So your output will be /var/www/../../../etc/passwd\0.php. The magic happens the moment PHP gives that string to C: C interprets the \0 character as string termination and thinks it got /var/www/../../../etc/passwd. And this file of course exists.

The fix

From the release notes:

Paths with NULL in them (foo\0bar.txt) are now considered as invalid. (Rasmus)

The fix mostly consists of adding if-clauses, comparing the string length with the c method (left) and the php method (right):

if (strlen(Z_STRVAL_PP(file)) != Z_STRLEN_PP(file)) {
  • But "file exists" was never printed?
    – gsgx
    Commented Aug 29, 2014 at 17:34
  • what's the output of dpkg -s php5 | grep 'Version'?
    – user10008
    Commented Aug 29, 2014 at 17:42
  • I'm asking, as ubuntu may have backported the patch...
    – user10008
    Commented Aug 29, 2014 at 19:49
  • Version: 1:5.2.17.dfsg.1-0jblgf1~lucid. The repositories only have 5.3.10, so I had to install it by downloading the deb files here. Also, the newer versions (at least php 5.5) with the patch don't show \0, they simply skip that byte.
    – gsgx
    Commented Aug 29, 2014 at 22:48
  • Unfortunately I can't tell whether a backport has been made from the changelog... Anyway it's very unlikely, as the bug is not this severe.
    – user10008
    Commented Aug 30, 2014 at 22:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .