目录
一、总述
发现方法:
代码审计
产生原因:
函数的使用不当、配置不当、代码逻辑漏洞
利用:
通过前端传入的值去覆盖程序中的局部变量或全局变量,从而达到变量覆盖
使用场景:
$$ 使用不当
extract() 、parse_str() 函数使用不当
import_request_variables() 使用不当,开启了全局变量注册(PHP 4 >= 4.1.0, PHP 5 < 5.4.0)
……
二、extract函数
语法:
extract(array,extract_rules,prefix)
参数 描述 array 必需。规定要使用的数组。 extract_rules 可选。extract() 函数将检查每个键名是否为合法的变量名,同时也检查和符号表中已存在的变量名是否冲突。对不合法和冲突的键名的处理将根据此参数决定。
可能的值:
- EXTR_OVERWRITE - 默认。如果有冲突,则覆盖已有的变量。
- EXTR_SKIP - 如果有冲突,不覆盖已有的变量。
- EXTR_PREFIX_SAME - 如果有冲突,在变量名前加上前缀 prefix。
- EXTR_PREFIX_ALL - 给所有变量名加上前缀 prefix。
- EXTR_PREFIX_INVALID - 仅在不合法或数字变量名前加上前缀 prefix。
- EXTR_IF_EXISTS - 仅在当前符号表中已有同名变量时,覆盖它们的值。其它的都不处理。
- EXTR_PREFIX_IF_EXISTS - 仅在当前符号表中已有同名变量时,建立附加了前缀的变量名,其它的都不处理。
- EXTR_REFS - 将变量作为引用提取。导入的变量仍然引用了数组参数的值。
prefix 可选。请注意 prefix 仅在 extract_type 的值是 EXTR_PREFIX_SAME,EXTR_PREFIX_ALL,EXTR_PREFIX_INVALID 或 EXTR_PREFIX_IF_EXISTS 时需要。如果附加了前缀后的结果不是合法的变量名,将不会导入到符号表中。
前缀和数组键名之间会自动加上一个下划线。
示例:
<?php
$a = false;
extract($_GET);
if ($a) {
echo "flag{...}";
} else {
echo "……";
}
?>extract函数将GET传入的数据转换为变量名和变量的值
输入?a=1可将$a的值变为true----->获得flag
三、parse_str函数
语法:
parse_str(string,array)
参数 描述 string 必需。规定要解析的字符串。 array 可选。规定存储变量的数组的名称。该参数指示变量将被存储到数组中。 未设置 array 参数,由该函数设置的变量将覆盖已存在的同名变量
parse_str函数的作用是解析字符串并注册成变量
在注册变量之前不会验证当前变量是否存在,直接覆盖掉已有变量
也就是把输入的字符串变成变量
示例:
<?php
$a = false;
parse_str($_SERVER['QUERY_STRING']);
if ($a) {
echo "flag{...}";
} else {
echo "……";
}
?>输入?a=1
四、import_request_variables函数
语法:
bool import_request_variables ( string $types [, string $prefix ] )
参数 描述 $types 指定需要导入的变量,可以用字母 G、P 和 C 分别表示 GET、POST 和 Cookie,这些字母不区分大小写,所以你可以使用 g 、 p 和 c 的任何组合。POST 包含了通过 POST 方法上传的文件信息。注意这些字母的顺序,当使用 gp 时,POST 变量将使用相同的名字覆盖 GET 变量。任何 GPC 以外的字母都将被忽略 $prefix 变量名的前缀,置于所有被导入到全局作用域的变量之前。所以如果你有个名为 userid 的 GET 变量,同时提供了 pref_ 作为前缀,那么你将获得一个名为 $pref_userid 的全局变量。虽然 prefix 参数是可选的,但如果不指定前缀,或者指定一个空字符串作为前缀,你将获得一个 E_NOTICE 级别的错误 PHP 4 >= 4.1.0, PHP 5 < 5.4.0
示例:
<?php
$a = false;
import_request_variables('G');
if ($a) {
echo "flag{...}";
} else {
echo "……";
}
?>排在前面的会覆盖排在后面的字符传入参数的值,若为“GP”,且GET和POST同时传入了a参数,则POST传入的a会被忽略
五、配置不当
前提:
当PHP配置register_globals=ON时,利用register_globals的特性,复现全局变量覆盖漏洞
示例:
<?php
if ($a) {
echo "flag{...}";
} else {
echo "……";
}
?>用户传入参数auth=1即可进入if语句块
如果在if语句前初始化$a变量,就不会触发了
六、代码逻辑漏洞
$$导致的变量覆盖
$$(可变变量)
一个变量的变量名可以动态的设置和使用
这个可变变量获取了一个普通变量的值作为这个可变变量的变量名
<?php
$a="hello";//赋值
$$a="everybody";
//使a变量的值作为变量名
echo "$a ${$a}";
//输出:hello everybody
echo "$a $hello";
//同样输出:hello everybody
?>
示例:
<?php
$a = false;
foreach($_GET as $key => $value){
$$key = $value;
}
if ($a) {
echo "flag{...}";
} else {
echo "……";
}
?>通过foreach循环遍历数组(如,$_GET、$_POST等),这里将GET传入的参数注册为变量,用户输入“?auth=1”就又成功绕过了判断,获得了flag