在尝试强化PHP网络应用程序null byte poisoning时,我注意到我在请求中实际发送一个空字节时有一段时间。
使用cURL,我终于能够找到一种在我的请求中发送空字节的方法,但我注意到一些非常奇怪的事情:没有请求参数,其值包含空字节到达我的PHP应用程序。
作为概念验证,我在服务器上创建了一个名为test.php
的文件:
<?php echo json_encode($_GET), PHP_EOL;
以下是对此脚本的一些请求的结果:
> 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"}
键似乎在空字节处被截断,如果该值包含空字节,则该参数将从请求数组中完全删除。
使用print_r()
会产生类似的结果:
<?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 )
如果我修改我的脚本和cURL请求以使用$_POST
,则会发生同样的事情。
不是我在抱怨,但我确实需要知道为什么会这样,这样我才能确保每个网络服务器都配置正确。
导致此行为的原因是什么?
> 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
答案 0 :(得分:3)
我指出PHP源代码的/main/SAPI.c的第1010行。
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()#defined为_estrdup(),位于/Zend/zend_alloc.c的第396行,并使用标准库函数strlen()和memcpy()进行出价。基本上estrdup()只会复制到空字节。
答案 1 :(得分:0)
在许多语言中,空字节表示字符串的结尾。我将数据作为十六进制发送并重新解释为服务器端。我认为GET不支持二进制文件。
答案 2 :(得分:0)
首先禁用Suhosin。它已经照顾好了。
只要你启用了它,你就不能轻易地注入NUL字节。
答案 3 :(得分:0)
<强> var_dump($your_url);
强>
如果它包含UGLY / NULL字符,那么首先尝试 TRIM()
。