您现在的位置是:首页 > 技术教程 正文

PHP变量覆盖--超详细

admin 阅读: 2024-03-17
后台-插件-广告管理-内容页头部广告(手机)

变量覆盖漏洞

看下面这个例子:

$a='hello'; $b='world'; $$a=$b; echo($hello);
  • 1
  • 2
  • 3
  • 4

最后的输出结果为world

这里先是定义了a,b两个变量,分别赋值hello和world。接着,$$a表示将变量a的值变成一个变量即$hello,然后将变量b的值赋给它,最后输出world。
所以在源码中看到$$可以想到变量覆盖漏洞。

同时,还有一些函数也会出现变量覆盖,这里我们就先看以下foreach函数
foreach函数会遍历数组,然后将键名与键值分别赋值给后面的变量,这样就容易产生变量覆盖漏洞

foreach($_GET['a'] as $key=>$value){ $$key=$value; }
  • 1
  • 2
  • 3

这里我传入参数?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

<?php $flag = file_get_contents('/flag'); //获取flag文件
  • 1
  • 2
  • 3

index.php(去掉其他源代码之后)

<?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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

一开始学完刚看到这题目,直接蒙了,然后就乖乖去学习大佬的wp了

一共有三种解法,分别对应了上面的三个exit()

第一种输出$handsome

要想得到flag,就要使$handsome=$flag,那么就能够想到前面的foreach函数

foreach($_GET as $x => $y){ $$x = $$y; }
  • 1
  • 2
  • 3

他能使flag覆盖handsome这个变量,那么payload就是?handsome=flag,当我们尝试着传入参数后,发现,并没有给我们flag,而是给我们返回了dog,也就是说它执行了下面这句,那么我们还需要传flag参数

if(!isset($_GET['flag']) && !isset($_POST['flag'])){ exit($yds); }
  • 1
  • 2
  • 3

而传入flag参数后就必然逃不过下面这个if,传入的flag参数的值要等于某一个键值名并且这个键值名不能为flag

if($_GET['flag'] === $x && $x !== 'flag'){ exit($handsome); }
  • 1
  • 2
  • 3

既然前面已经传了一个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); }
  • 1
  • 2
  • 3

那么我们就可以直接利用变量覆盖将$flag覆盖$yds,构造?yds=flag得到flag
在这里插入图片描述

第三种输出$is

满足传入的flag参数等于'flag'就行,也就是说直接传flag=flag

if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){ exit($is); }
  • 1
  • 2
  • 3

构造?is=flag&flag=flag得到flag
在这里插入图片描述

到这里这道题就结束了,但是我一直在想最后的echo能不能被利用输出flag,发现并不能,无论你怎么构造,都逃不过那三个exit(),最后的echo就是来迷惑你的,想让我这样的新手不去想变量覆盖。。。。

好了变量覆盖的学习就到这里。

参考:[BJDCTF2020]Mark loves cat(3种解法)

标签:
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

在线投稿:投稿 站长QQ:1888636

后台-插件-广告管理-内容页尾部广告(手机)
关注我们

扫一扫关注我们,了解最新精彩内容

搜索