变量覆盖漏洞是指可以用我们自定义的参数值替换程序原有的变量值,从而产生漏洞。大多都是由于函数使用不当导致,经常导致变量覆盖漏洞的函数有:extract()函数、parse_str()函数、import_request_variables()函数,另外有些利用$$的方式注册变量没验证已有变量导致覆盖也是经常出现的。下面就对这四种情况做简要分析:
(1)extract()函数:
extract()函数从数组中将变量导入到当前的符号表,也就是将数组中的键值对注册成变量。其最多有三个参数,语法为:
extract(array,extract_rules,prefix)
参数 | 描述 |
---|---|
array | 必需。规定要使用的数组。 |
extract_rules | 可选。extract() 函数将检查每个键名是否为合法的变量名,同时也检查和符号表中已存在的变量名是否冲突。对不合法和冲突的键名的处理将根据此参数决定。 可能的值:
|
prefix | 可选。请注意 prefix 仅在 extract_type 的值是 EXTR_PREFIX_SAME,EXTR_PREFIX_ALL,EXTR_PREFIX_INVALID 或 EXTR_PREFIX_IF_EXISTS 时需要。如果附加了前缀后的结果不是合法的变量名,将不会导入到符号表中。 前缀和数组键名之间会自动加上一个下划线。 |
可以看出,第一个参数是必须的,是否导致变量覆盖漏洞由第二个参数决定。有如下三种情况会产生漏洞:
一:只传入一个参数时,默认为EXTR_OVERWRITE模式,表示如果有冲突,则覆盖已有的变量;
二:第二个参数为EXTR_OVERWRITE时;
三:第二个参数为EXTR_IF_EXISTS时,表示仅在当前符号表中已有同名变量时,覆盖它们的值,其它的都不处理。
测试代码如下:
'2');
extract($b);
print_r($a);
?>
测试结果如下:
原本变量$a的值为1,经过extract()函数并且只传入一个参数后,$a的值被成功覆盖成了2。
(2)parse_str()函数:
parse_str()函数把查询字符串解析到变量中,并且不会验证当前变量是否已经存在。parse_str()函数语法为:
parse_str(string,array)
第一个参数是必需的,代表 要解析注册成变量的字符串。第二个参数是一个数组,当其存在时,注册的变量会放到这个数组里,但是如果数组原来就存在相同的键,则会覆盖掉原来的键值。
测试代码如下:
测试结果如下:
变量$a的值经过parse_str()函数从原来的1被覆盖成了2。
(3)import_request_variables()函数:
import_request_variables()函数把GET、POST、Cookie变量导入到全局作用域中,用在register_globals被禁止时,版本需要PHP 4 >= 4.1.0和 PHP 5 < 5.4.0。import_request_variables()函数语法为:
bool import_request_variables ( string $types [, string $prefix ] )
types
参数指定需要导入的变量。可以用字母‘G’、‘P’和‘C’分别表示 GET、POST 和 Cookie。这些字母不区分大小写,所以你可以使用‘g’、‘p’和‘c’的任何组合。prefix
参数作为变量名的前缀,置于所有被导入到全局作用域的变量之前。
测试代码如下:
测试结果如下:
变量$a的值被覆盖成了2。
(4)$$变量覆盖:
相信大家都见过这段代码:
foreach(array('_COOKIE', '_POST', '_GET') as $_request){
foreach($$_request as $_key => $_value){
$$_key = addslashes($_value);
}
}
当$_key为COOKIE、POST、GET中的参数,比如提交?a=1,则$key的值为a,而还有一个$在a的前面,结合起来则是$a=addslashes($_value);所以会覆盖已有的变量$a的值。测试代码如下:
$_value) {
echo $_key.'
';
$$_key = addslashes($_value);
}
}
echo $a;
?>
测试结果如下:
成功把变量$a的值覆盖成了2。
以上就是导致变量覆盖漏洞的四种情况。变量覆盖漏洞最常见漏洞点是在左边梁注册时没有验证变量是否存在,以及在赋值给变量的时候,所以尽量使用原始的变量数组,如$_GET、$_POST,或者在注册变量前一定要验证变量是否存在。