目录
变量和变量覆盖
可变变量
一个可变变量 “$$” 获取了一个普通变量的值后,用这个值作为这个可变变量的变量名。一个美元符号表示提取变量中的值,而 2 个连续的美元符号表示用某个变量的内容作为变量名,再来访问该变量。例如以下代码:
<?php
$a = "b";
$b = "c";
$c = "a";
echo $a; //输出 b
echo $$a; //输出 c
echo $$$a; //输出 a
?>
超全局变量
PHP 的 $ GLOBALS 是一个超全局变量,它引用全局作用域中可用的全部变量。变量时一个包含了全部变量的全局组合数组,变量的名字就是数组的键。有时候当 flag 隐藏在某个变量中时,可以考虑从 GLOBALS 中得到。
变量覆盖
extract() 函数从数组中将变量导入到当前的符号表。使用数组键名作为变量名,使用数组键值作为变量值,针对数组中的每个元素将在当前符号表中创建对应的一个变量。extract() 函数也可以将 GET 传入的数据进行转换,例如:
<?php
$a = false;
extract($_GET);
if($flag)
{
echo "flag{}"
}
?>
此时变量 a 已经被定义了,但是在 extract() 函数转换 GET 方法传入的数据时,传入的 a 在转换时就会把原来的变量覆盖掉。
例题:变量 1
打开网页,可以直接看到源码。
flag In the variable ! <?php
error_reporting(0); // 关闭php错误显示
include "flag1.php"; // 引入 flag1.php 文件代码
highlight_file(__file__);
if(isset($_GET['args'])){ // 通过get方式传递 args变量才能执行if里面的代码
$args = $_GET['args'];
if(!preg_match("/^\w+$/",$args)){ // 匹配任意大小写字母和 0 到 9 以及下划线组成
die("args error!");
}
eval("var_dump($$args);"); //var_dump() 函数用于输出变量的相关信息
}
?>
因为这里有个 preg_match() 函数,它会通过正则表达式匹配字符串,因此不能使用其他的漏洞。根据提示 flag 藏在一个变量之中,观察到代码中有“$$”的可变变量用法。
也就是说,此时不需要去猜测 flag 藏在那个变量中,因为知道了变量名,有了“$$”也不能直接访问。现在需要知道保存 flag 的变量是哪个变量的值,因为 var_dump() 函数可以输出变量,如果变量是个数组也可以,例如:
<?php
$args = array(1, 2, 3);
var_dump($args);
?>
则数组 args 中的内容都可以被输出来,因此该函数也能把 “$GLOBALS” 中的内容都输出来。因此我们只需要把 GLOBALS 传递过去就行,构造 payload:
http://123.206.87.240:8004/index1.php?args=GLOBALS
例题:extract 变量覆盖
源码如下,flag 变量已经被定义了,如果用 GET 传入的变量中存在一个名叫 shiyan 的字符串,则将 flag 变量的值赋给 content 变量,如果变量 shiyan 和变量 content 的值相同就输出 flag 的值。
<?php
$flag='xxx';
extract($_GET);
if(isset($shiyan))
{
$content=trim(file_get_contents($flag));
if($shiyan==$content)
{
echo'flag{xxx}';
}
else
{
echo'Oh.no';
}
}
?>
此时 flag 变量被赋值成什么值我们不得而知,所以现在的想法是把 flag 变量覆盖掉。由于 extract() 函数可以将所有 GET 方法传入的数据全部换成变量,因此可以在传入 shiyan 变量时也传入一个 flag 变量。构造 payload 提交到指定网页,提交获得 flag。
?shiyan=&flag=