变量覆盖 学习笔记
变量覆盖
相关文章 & Source & Reference
$$导致的变量覆盖问题
$$介绍
$$这种写法称为可变变量
一个可变变量获取了一个普通变量的值作为这个可变变量的变量名。
<?php
$a = "hello";
echo "$a"; //输出hello
$a="world";
echo "$a"; //输出hello
echo "$$a"; //输出word
echo "$a ${$a}"; //输出hello world
echo "$a $hello"; //输出hello world
?>
漏洞产生
使用 foreach 来遍历数组中的值,然后再将获取到的数组键名作为变量,数组中的键值作为变量的值。因此就产生了变量覆盖漏洞。
例如
<?php
foreach ($_GET as $key => $value) {
${$key} = $value;
}
echo $a;
?>
get 得到的数据 $key 和 $value, 关键第 3 行,${$key} 用 get 传进来的 $key 做为新的变量, 将 get 传进来的 $value 赋值给它。
get ?a=1 第 3 行会解析为 $a=1。就造成了变量覆盖。
extract()函数使用不当
extract()函数从数组中将变量导入到当前的符号表。该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
extract(array &$array, int $flags = EXTR_OVERWRITE, string $prefix = ""): int
第一个参数是必须的,会不会导致变量覆盖漏洞由第二个参数决定,该函数有三种情况会覆盖已有变量。
例如
<?php
$a = 1; //原变量值为1
$b = array('a' => '3');
extract($b); //经过extract()函数对$b处理后
echo $a; //输出结果为3
?>
又例如
<?php
$a = "0";
extract($_GET);
if ($a == 1) {
echo "Hacked!";
} else {
echo "Hello!";
}
?>
?a=1 就可以覆盖 a
例题
extract($_GET);
if(isset($bdctf))
{
$content=trim(file_get_contents($flag)); //file_get_contents—将整个文件读入一个字符串
if($bdctf==$content) //trim—去除字符串首尾处的空白字符(或者其他字符)
{ echo'bdctf{**********}'; }
else
{ echo'这不是蓝盾的密码啊'; }
}
题目使用了 extract($_GET)
接收了 GET 请求中的数据,并将键名和键值转换为变量名和变量的值,然后再进行两个 if 的条件判断,所以可以使用 GET 提交参数和值,利用 extract() 对变量进行覆盖,从而满足各个条件。
使 $bdctf 与 $content 都为空或者不存在就满足 $bdctf==$content
get ?flag=&bdctf=
得到 flag
parse_str()函数使用不当
parse_str(string $string, array &$result): void
如果未设置 array 参数,由该函数设置的变量将覆盖已存在的同名变量。
php.ini 文件中的 magic_quotes_gpc 设置影响该函数的输出。如果已启用,那么在 parse_str() 解析之前,变量会被 addslashes() 转换。
parse_str 函数的作用就是解析字符串并注册成变量,在注册变量之前不会验证当前变量是否存在,所以直接覆盖掉已有变量
例如
<?php
$a = 1; //原变量值为1
parse_str('a=2'); //经过parse_str()函数后注册变量$a,重新赋值
print_r($a); //输出结果为2
?>
例题
<?php
error_reporting(0);
if(
empty($_GET['id'])) { //empty()检查是否为空
show_source(__FILE__); //highlight_file—语法高亮一个文件
die(); //等同于exit—输出一个消息并且退出当前脚本
} else {
include (‘flag.php’);
$a = "test";
$id = $_GET['id'];
@parse_str($id);
if ($a[0] != ‘QNKCDZO’ && md5($a[0]) == md5(‘QNKCDZO’)) {
echo $flag;
} else {
exit(‘其实很简单其实并不难!’);
}
}
?>
PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。
这里其实利用了弱类型的知识点
使用get请求 ?id=a[0]=s878926199a
得到flag
mb_parse_str()变量覆盖
mb_parse_str()函数用于解析GET/POST/COOKIE数据并设置全局变量,和parse_str()类似:
<?php
$a = 'oop';
mb_parse_str($_SERVER["QUERY_STRING"]);
if ($a == 'test') {
echo "Hacked!";
} else {
echo "Hello!";
}
?>
register_globals全局变量覆盖
注:register_globals 已自 PHP 5.3.0 起废弃并将自 PHP 5.4.0 起移除。
php.ini 中有一项为 register_globals,即注册全局变量,当 register_globals=On 时,传递过来的值会被直接的注册为全局变量直接使用,而 register_globals=Off 时,我们需要到特定的数组里去得到它。
当register_globals=On,变量未被初始化且能够用户所控制时,就会存在变量覆盖漏洞:
<?php
echo "Register_globals: " . (int)ini_get("register_globals") . "<br/>";
if ($a) {
echo "Hacked!";
}
?>
通过 GET 和 POST 方式输入变量 a 的值都可以覆盖 a
从 cookie 里也可以
import_request_variables()使用不当
import_request_variables 好像比较难见到了
例如
<?php
$auth='0';
import_request_variables('G');
if($auth== 1){
echo"private!";
}else{
echo"public!";
}
?>
get auth=1时,网页上会输出private!
import_request_variables('G')指定导入GET请求中的变量,从而导致变量覆盖
点击关注,共同学习!
安全狗的自我修养