解题
得到两个文件
flag.php
<?php
$flag = file_get_contents('/flag');
index.php
<?php
include 'flag.php';
$yds = "dog";
$is = "cat";
$handsome = 'yds';
foreach($_POST as $x => $y){
$$x = $y;
}
foreach($_GET as $x => $y){
$$x = $$y;
}
foreach($_GET as $x => $y){
if($_GET['flag'] === $x && $x !== 'flag'){
exit($handsome);
}
}
if(!isset($_GET['flag']) && !isset($_POST['flag'])){
exit($yds);
}
if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){
exit($is);
}
echo "the flag is: ".$flag;
代码审计
- 前两个foreach语句分别将POST参数和GET参数进行变量覆盖,接着是三个if语句,exit()函数退出脚本的同时输出变量,最后一句是输出我们想要的flag。
- 首先我们想到的是让脚本执行到最后一句
echo $flag
;,但即使绕过三个if语句,我们GET传参或者POST传参的flag总会被变量覆盖:如我们GET传参flag=aaa,在第二个foreach语句中变成$flag = $aaa
,而$aaa
变量没有定义为空,最后的输出就是空 - 由此看来,这样行不通,回过头来前面说到if语句中的exit()函数虽然会退出执行,但也会输出其参数,我们可以利用变量覆盖将exit()函数内的参数用$flag覆盖掉就能输出flag了
- 思路理清了,这里面有三个if语句,其中有两个能利用变量覆盖输出flag,也就是说有两种方法
一是第二个if语句中可以看到这里是输出的$yds变量,那么我们就要通过变量覆盖达到$yds=$flag的效果,GET传参yds=flag,在第二个foreach语句中,首先是$x=yds
,$y=flag
,经过$$x = $$y
也就变成了$yds=$flag
,这是其一;
二是第三个if语句中输出变量$is,判断条件为$_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'
,这里可以通过满足后面这个条件进行变量覆盖:GET传参is=flag&flag=flag;在第二个foreach语句中,首先是$x=is
,$y=flag
,带进去就变成了$is=$flag
,这就达到了覆盖的目的,而参数中flag=flag只是为了满足if语句;