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

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.

链接地址: http://www.djcxy.com/p/11166.html

上一篇: RazorEngine内存使用情况

下一篇: 什么导致请求中的空字节值被过滤掉?