本文主要研究PHP的GET/POST/COOKIE大变量生成过程,及可能在WAF流量层面绕过的一些TRICKS
实验环境:PHP 7.3.4 在FPM模式下运行
PHP变量处理的主要代码在main/php_variables.c,调用栈如下:
由于代码流程过长,本文不贴出具体代码,但是会在相应地方给出github链接供参考
PHP示例代码
<?phpecho "get:";var_dump($_GET);echo "cookie:";var_dump($_COOKIE);echo "post:";var_dump($_POST);
以解析$_GET
变量为例,大致流程为:获取请求字符串-->获取分割符&
-->使用=
分割key和value。
在解析key和value时,会分别对其进行url解码,关键代码如下:
if (val) { /* have a value */
size_t val_len;
size_t new_val_len;*val++ = '';
// 对key进行url解码
php_url_decode(var, strlen(var));
// 对value进行url解码
val_len = php_url_decode(val, strlen(val));
val = estrndup(val, val_len);
if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len)) {
php_register_variable_safe(var, val, new_val_len, &array);
}
efree(val);
}
我们知道00
在C语言中意味着字符串的结尾,其编码为%00
。
在对key进行url解码之后,%00
转换为00
而截断了key字符串。
但是对value进行url解码的时候,获取了其返回值val_len
,即字符串长度,后续注册变量时,也是使用val_len
进行内存中的操作,所以未能截断value的值
URL 不能包含空格。URL 编码通常使用 + 来替换空格
使用%20
替换空格
在注册变量时,PHP会对变量名进行判断,丢弃变量名前的空格,关键代码如下:
while (*var_name==' ') {
var_name++;
}
.
会转化为_
首先明确一个问题,PHP的变量名中是不能包含点号的。但是为了处理表单中的点号命名,PHP就会自动把点号.
转换成下划线_
。
这个转换的过程也是发生在PHP变量的注册过程中,关键代码如下:
/* ensure that we don't have spaces or dots in the variable name (not binary safe) */
for (p = var; *p; p++) {
if (*p == ' ' || *p == '.') {
*p='_';
} else if (*p == '[') {
is_array = 1;
ip = p;
*p = 0;
break;
}
}
[
会转换为_
这个转换过程与.
的转换过程不同。PHP在遇到[
符号时,会认为变量为数组。后续进行数组处理时,如果未能找到与[
匹配的]
,则会将[
替换为.
。关键代码如下:
ip = strchr(ip, ']');
if (!ip) {
/* PHP variables cannot contain '[' in their names, so we replace the character with a '_' */
*(index_s - 1) = '_';index_len = 0;
if (index) {
index_len = strlen(index);
}
goto plain_var;
return;
}
https://www.laruence.com/2008/11/07/581.html
侵权请私聊公众号删文
本文作者:Lemon
本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/190540.html