变量覆盖 学习笔记

变量覆盖


相关文章 & 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请求中的变量,从而导致变量覆盖
点击关注,共同学习!
安全狗的自我修养

github haidragon

https://github.com/haidragon

posted @ 2022-10-31 15:25  syscallwww  阅读(27)  评论(0编辑  收藏  举报