变量覆盖
相关文章 & Source & Reference
$$导致的变量覆盖问题
$$介绍
$$这种写法称为可变变量
一个可变变量获取了一个普通变量的值作为这个可变变量的变量名。
- $a = "hello";
- echo "$a"; //输出hello
- $a="world";
- echo "$a"; //输出hello
- echo "$$a"; //输出word
- echo "$a ${$a}"; //输出hello world
- echo "$a $hello"; //输出hello world
- ?>
漏洞产生
使用 foreach 来遍历数组中的值,然后再将获取到的数组键名作为变量,数组中的键值作为变量的值。因此就产生了变量覆盖漏洞。
例如
- 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
第一个参数是必须的,会不会导致变量覆盖漏洞由第二个参数决定,该函数有三种情况会覆盖已有变量。
例如
- $a = 1; //原变量值为1
- $b = array('a' => '3');
- extract($b); //经过extract()函数对$b处理后
- echo $a; //输出结果为3
- ?>
又例如
- $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 函数的作用就是解析字符串并注册成变量,在注册变量之前不会验证当前变量是否存在,所以直接覆盖掉已有变量
例如
- $a = 1; //原变量值为1
- parse_str('a=2'); //经过parse_str()函数后注册变量$a,重新赋值
- print_r($a); //输出结果为2
- ?>
例题
- 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()类似:
- $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,变量未被初始化且能够用户所控制时,就会存在变量覆盖漏洞:
- echo "Register_globals: " . (int)ini_get("register_globals") . "
"; -
- if ($a) {
- echo "Hacked!";
- }
- ?>
通过 GET 和 POST 方式输入变量 a 的值都可以覆盖 a
从 cookie 里也可以
import_request_variables()使用不当
import_request_variables 好像比较难见到了
例如
- $auth='0';
- import_request_variables('G');
- if($auth== 1){
- echo"private!";
- }else{
- echo"public!";
- }
- ?>
get auth=1时,网页上会输出private!
import_request_variables('G')指定导入GET请求中的变量,从而导致变量覆盖
点击关注,共同学习!安全狗的自我修养
