变量覆盖漏洞
看下面这个例子:
$a='hello';
$b='world';
$$a=$b;
echo($hello);
最后的输出结果为world
这里先是定义了a,b两个变量,分别赋值hello和world。接着,$$a表示将变量a的值变成一个变量即$hello,然后将变量b的值赋给它,最后输出world。 所以在源码中看到$$可以想到变量覆盖漏洞。
同时,还有一些函数也会出现变量覆盖,这里我们就先看以下foreach函数 foreach函数会遍历数组,然后将键名与键值分别赋值给后面的变量,这样就容易产生变量覆盖漏洞
foreach($_GET['a'] as $key=>$value){
$$key=$value;
}
这里我传入参数?a=hello,那么就相当于我传入了一组键值对,键名为a,键值为hello(即$key=a,$value=hello),接着执行$$key=$value,这里就会变成$hello=hello 其他一些函数其实大同小异,在题目中遇到了再做了解吧 下面来看一道题目
[BJDCTF2020]Mark loves cat
进入靶机,看到如下网页 到处浏览,点一点,感觉没什么东西,页面源代码也没什么有用的,想用dirsearch扫一下文件路径,但是一直报429,弄了好久没法解决,就不耐烦看了眼大佬的wp,发现有git源码泄露,就用githack还原了一下,还原出两个文件,分别是flag.php与index.php 都打开看一下
flag.php
$flag = file_get_contents('/flag'); //获取flag文件
index.php(去掉其他源代码之后)
include 'flag.php'; //包含flag.php文件
$yds = "dog";
$is = "cat";
$handsome = 'yds';
foreach($_POST as $x => $y){ //遍历post传入的数据,然后将值赋给以值命名的变量
$$x = $y;
}
foreach($_GET as $x => $y){ //遍历get传入的数据,然后使分别以变量名与值命名的变量相等
$$x = $$y;
}
foreach($_GET as $x => $y){ //遍历get传入的数据
if($_GET['flag'] === $x && $x !== 'flag'){ //传入的flag参数的值要等于某一个键值名并且这个键值名不能为flag
exit($handsome); //满足条件,退出并输出$handsome
}
}
if(!isset($_GET['flag']) && !isset($_POST['flag'])){ //判断get与post是否传参flag
exit($yds); //如果都没传入flag,则退出并输出$yds
}
if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){ //post或get有一个传入flag参数并且值为flag即可满足条件
exit($is); //满足条件,退出并输出$is
}
echo "the flag is: ".$flag; //输出flag
一开始学完刚看到这题目,直接蒙了,然后就乖乖去学习大佬的wp了
一共有三种解法,分别对应了上面的三个exit()
第一种输出$handsome
要想得到flag,就要使$handsome=$flag,那么就能够想到前面的foreach函数
foreach($_GET as $x => $y){
$$x = $$y;
}
他能使flag覆盖handsome这个变量,那么payload就是?handsome=flag,当我们尝试着传入参数后,发现,并没有给我们flag,而是给我们返回了dog,也就是说它执行了下面这句,那么我们还需要传flag参数
if(!isset($_GET['flag']) && !isset($_POST['flag'])){
exit($yds);
}
而传入flag参数后就必然逃不过下面这个if,传入的flag参数的值要等于某一个键值名并且这个键值名不能为flag
if($_GET['flag'] === $x && $x !== 'flag'){
exit($handsome);
}
既然前面已经传了一个handsome参数,那我们就构造?handsome=flag&flag=handsome,输入后,发现如下直接返回了flag,也就是说,代码退出了并输出了$handsome
应该有同学会想,我将两个参数换个位置变为?flag=handsome&handsome=flag可不可以,尝试一下你就会发现,输出yds而不是flag,因为在一开始foreach循环的时候,flag就被handsome覆盖掉了,后面flag就一直是yds。
第二种输出$yds
这种方法就简单了,我们在上面直接传?handsome=flag的时候发现,页面只返回了dog,也就是说在不传入flag的情况下会输出$yds
if(!isset($_GET['flag']) && !isset($_POST['flag'])){
exit($yds);
}
那么我们就可以直接利用变量覆盖将$flag覆盖$yds,构造?yds=flag得到flag
第三种输出$is
满足传入的flag参数等于'flag'就行,也就是说直接传flag=flag
if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){
exit($is);
}
构造?is=flag&flag=flag得到flag
到这里这道题就结束了,但是我一直在想最后的echo能不能被利用输出flag,发现并不能,无论你怎么构造,都逃不过那三个exit(),最后的echo就是来迷惑你的,想让我这样的新手不去想变量覆盖。。。。
好了变量覆盖的学习就到这里。
参考:[BJDCTF2020]Mark loves cat(3种解法)
推荐阅读
发表评论