What is causing null byte values in request to get filtered out?

While trying to harden a PHP web app against null byte poisoning, I noticed that I was having a heck of a time actually sending a null byte in my request.

Using cURL, I was finally able to find a way to send null bytes in my requests, but I noticed something very odd: No request parameters whose values include a null byte ever reach my PHP application.

As a proof of concept, I created a file named test.php on my server:

<?php echo json_encode($_GET), PHP_EOL;

Here's the result of some requests to this script:

> curl 'http://localhost/test.php?foo=bar&baz=nu%00ll'
{"foo":"bar"}

> curl 'http://localhost/test.php?foo=bar&b%00az=null'
{"foo":"bar","b":"null"}

It appears that keys are getting truncated at the null byte, and if the value contains a null byte, the parameter is removed from the request array entirely.

Using print_r() yields similar results:

<?php print_r($_GET);
> curl 'http://localhost/test.php?foo=bar&baz=nu%00ll'
Array
(
    [foo] => bar
)

> curl 'http://localhost/test.php?foo=bar&b%00az=null'
Array
(
    [foo] => bar
    [b] => null
)

Same thing happens if I modify my script and cURL requests to use $_POST.

Not that I'm complaining, but I do need to know why this is happening so that I can ensure that each webserver is configured correctly.

What is causing this behavior?

> php -v

PHP 5.3.3 (cli) (built: Jul  3 2012 16:40:30) 
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
    with Suhosin v0.9.29, Copyright (c) 2007, by SektionEins GmbH

Answers


Disable Suhosin first. It takes care of that already.

As long as you have enabled it, you can not inject NUL bytes that easily.


I point you to line 1010 of /main/SAPI.c of the PHP source code.

SAPI_API char *sapi_getenv(char *name, size_t name_len TSRMLS_DC)
{
    if (sapi_module.getenv) { 
        char *value, *tmp = sapi_module.getenv(name, name_len TSRMLS_CC);
        if (tmp) {
            value = estrdup(tmp);
        } else {
            return NULL;
        }
        if (sapi_module.input_filter) {
            sapi_module.input_filter(PARSE_ENV, name, &value, strlen(value), NULL TSRMLS_CC);
        }
        return value;
    }
    return NULL;
}

estrdup() is #defined to _estrdup() which is on line 396 of /Zend/zend_alloc.c and makes use of both the standard library functions strlen() and memcpy() to do its bidding. Basically estrdup() will only copy up to a null byte.


In many languages, a null byte symbolizes the end of a string. I'd send the data as hex and reinterpret it server side. I don't think GET supports binary.


var_dump($your_url); If it contains UGLY/NULL characters, then try to TRIM() it at first.


Need Your Help

Way to control the order of concatenation with browserify?

javascript browserify

Say I have two files, a.ts and b.ts. a.ts has a class that extends from b.ts. If I attempt to browserify them using browserify a.ts b.ts -p [ tsify --target='ES5' ] &gt; test.js then the outputted ...

Newtonsoft JsonConvert with non-standard keys?

.net json wpf

I am using NewtonSoft's JsonConvert for .NET. I am retrieving my json from here:

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.