变量覆盖漏洞 [BJDCTF2020]Mark loves cat 1

2023-12-20 13:33:00

打开题目

我们拿dirsearch扫描一下看看

扫描得到

看见有git字眼,那我们就访问

用githack去扒一下源代码看看

可以看到确实有flag.php结合index.php存在

但是当我去翻源代码的时候却没有翻到

去网上找到了这道题目的源代码

<?php

include '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不是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;
}

我们用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' 赋给它。

这种方式可以创建和覆盖变量。

文章来源:https://blog.csdn.net/m0_75178803/article/details/135097123
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。