打开题目
我们拿dirsearch扫描一下看看
扫描得到
看见有git字眼,那我们就访问
用githack去扒一下源代码看看
可以看到确实有flag.php结合index.php存在
但是当我去翻源代码的时候却没有翻到
去网上找到了这道题目的源代码
<?phpinclude 'flag.php';$yds = "dog";
$is = "cat";
$handsome = 'yds';foreach($_POST as $x => $y){ $$x = $y ; //post 声明至当前文件
}foreach($_GET as $x => $y){ $$x = $$y; //GET型变量重新赋值为当前文件变量中以其值为键名的值
}foreach($_GET as $x => $y){if($_GET['flag'] === $x && $x !== 'flag'){ //传入的变量为flag value不是flagexit($handsome);}
}if(!isset($_GET['flag']) && !isset($_POST['flag'])){ exit($yds);
}if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){ exit($is);
}echo "the flag is: ".$flag;
}
我们用seay代码审计一下看看可能存在哪些漏洞
可以看到网页的源代码双$$符号可能存在变量覆盖漏洞
现在我们来逐一看看源代码分析语句
include 'flag.php';
$yds = "dog";
$is = "cat";
$handsome = 'yds';foreach($_POST as $x => $y){
$$x = $y ;
}
首先,包含了一个flag.php文件,将dog值和cat值分别赋给yds和is,字符串 'yds'
赋值给 $handsome
变量,foreach($_POST as $x => $y)
的作用是遍历 $_POST
数组,对于每一个键值对,将键赋值给变量 $x
,将值赋值给变量 $y。$$x = $y;
是一个动态变量赋值语法
foreach($_GET as $x => $y){
$$x = $$y;
}foreach($_GET as $x => $y){
if($_GET['flag'] === $x && $x !== 'flag'){
exit($handsome);
其次,foreach的作用是遍历$_GET数组,将键值赋值给变量$x,将值赋值给变量 $y。$$x = $y;
是一个动态变量赋值语法。这个方式可以创建和覆盖变量。
然后再用foreach遍历$_GET数组,在其后跟了一个if语句,它检查是否当前迭代的键 $x
的值等于 $_GET['flag']
的值,并且 $x
不等于字符串 'flag',
如果条件成立,就会执行下面的代码块,exit($handsome);
如果条件成立,exit($handsome);
会立即终止脚本的执行,并输出变量 $handsome
的值。
if(!isset($_GET['flag']) && !isset($_POST['flag'])){
exit($yds);
}if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){
exit($is);
}echo "the flag is: ".$flag;
}
if(!isset($_GET['flag']) && !isset($_POST['flag'])){ exit($yds); }
:这是一个条件语句。它首先检查是否 'flag' 参数既不在 $_GET
中,也不在 $_POST
中。isset
函数用于检查变量是否已设置并且不为 null
。如果条件成立,即 'flag' 参数既不在 GET 请求中,也不在 POST 请求中,那么脚本会立即退出,并输出 $yds
变量的值。
if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){ exit($is); }
:这是另一个条件语句。它检查是否 'flag' 参数的值在 POST 请求中等于字符串 'flag',或者在 GET 请求中等于字符串 'flag'。如果条件成立,脚本会退出并输出 $is
变量的值。
echo "the flag is: ".$flag;
:这段代码在前两个条件都不成立的情况下执行,输出一个字符串 "the flag is: " 以及变量 $flag
的值。
解法1 exit($handsome);
关键代码
foreach($_GET as $x => $y){
$$x = $$y;foreach($_GET as $x => $y){
if($_GET['flag'] === $x && $x !== 'flag'){
exit($handsome);
}
}
进入条件,我们先get传入?flag=a&a=flag,所以x=flag,y=a,$flag=$a; x=a,y=flag,$a=$flag
然后经过foreach函数时,
函数判断到 a=flag
的时候, $_GET['flag'] === $x && $x !== 'flag'
--> a === a && a !== 'flag'
这就进来了 true && true
就进来了, 然后 exit($handsome);
payload为:
get传参 /?yds=flag
getc传参 /?is=flag&flag=flag
查看页面源代码得到flag
参考wp:
https://www.cnblogs.com/Nestar/p/15922456.html
知识点:
-
forEach
forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。forEach(): 没有返回值,本质上等同于 for 循环,forEach 是不改变原数组
注意: forEach() 对于空数组是不会执行回调函数的
-
foreach和for循环语句既有相似点也有不同点
详情见:for循环和forEach的区别,看着一篇就够了! - 知乎
首先 for循环的执行 只能是通过循环生成索引下标数值 然后通过索引下标 操作 数组的数据元素
但是 forEach 可以通过设定参数 来 存储 索引下标 数据数值 这样在操作上更加的便利
例如:
foreach($_POST as $x => $y)
作用是遍历 $_POST
数组,对于每一个键值对,将键赋值给变量 $x
,将值赋值给变量 $y
如果 $_POST
包含如下数据
$_POST = array('username' => 'john_doe','password' => 'secure_password',// other form fields...
);
在 foreach($_POST as $x => $y)
循环中,第一次迭代时,$x
将被赋值为 'username'
,$y
将被赋值为 'john_doe'
;第二次迭代时,$x
将被赋值为 'password'
,$y
将被赋值为 'secure_password'
,依此类推
同样
如果语句变成了
foreach($_POST as $x => $y){
$$x = $y ;
}
例如,如果 $_POST
包含以下数据
$_POST = array('username' => 'john_doe','password' => 'secure_password',// other form fields...
);
在 foreach
循环中,第一次迭代时,$x
将被赋值为 'username'
,$y
将被赋值为 'john_doe'
。接着,$$x = $y;
将会执行,它实际上等同于 $username = 'john_doe';
。换句话说,它创建了一个名为 $username
的变量,并将 'john_doe'
赋给它。
同理,第二次迭代时,$x
被赋值为 'password'
,$y
被赋值为 'secure_password'
,所以 $$x = $y;
将执行 $password = 'secure_password';
,创建了一个名为 $password
的变量并将 'secure_password'
赋给它。
这种方式可以创建和覆盖变量。