变量覆盖漏洞

看下面这个例子:

$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种解法)

推荐阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: