php变量覆盖

参考博客

$$覆盖

$与$$区分

在PHP中,$ 和 $$ 的区别主要体现在变量的使用方式上。

$:这是普通的变量符号,用于定义和访问一个变量。比如:

$var = "Hello, World!";
echo $var;  // 输出:Hello, World!

$$:这是可变变量(Variable Variables),即变量的名称是另一个变量的值。通过 $$,你可以动态地访问或设置变量名。比如:

$var = "name";
$$var = "John";

这里,$$var 实际上是 $name,因此它相当于:

$name = "John";

也就是说,$var 的值是 "name",所以 $$var 等同于 $name,最终 $name 的值被设置为 "John"。

$$ 导致的变量覆盖问题在CTF代码审计题目中经常在foreach中出现,如以下的示例代码,使用foreach来遍历数组中的值,然后再将获取到的数组键名作为变量,数组中的键值作为变量的值。因此就产生了变量覆盖漏洞。请求?name=test 会将$name的值覆盖,变为test。

<?php
   //?name=test
   
   //output:string(4) “name” string(4) “test” string(4) “test” test
   
   $name=’thinking’;

   foreach ($_GET as $key => $value)
   {
       $$key = $value;
   }
   var_dump($key);
   var_dump($value);
   var_dump($$key);

   echo $name;
?>

CTF中$$导致的变量覆盖问题的例题1:

题目源码:

<?php
   include “flag.php”;

   $_403 = “Access Denied”;

   $_200 = “Welcome Admin”;

   if ($_SERVER["REQUEST_METHOD"] != “POST”)
   {
         die(“BugsBunnyCTF is here :p…”);
   }
   if ( !isset($_POST["flag"]) )
   {
         die($_403);
   }
   foreach ($_GET as $key => $value)
   {
         $$key = $$value;
   }
   foreach ($_POST as $key => $value)
   {
         $$key = $value;
   }
   if ( $_POST["flag"] !== $flag )
   {
         die($_403);
   }
   echo “This is your flag :. $flag . “\n”;
   die($_200);
?>

题目分析:

源码包含了flag.php文件,并且需要满足3个if里的条件才能获取flag,题目中使用了两个foreach并且也使用了$$.两个foreach中对 $$key的处理是不一样的,满足条件后会将$flag里面的值打印出来,所以$flag是在flag.php文件文件中的。

解题方法:

由于第7,11-14行间的代码会将$flag的值给覆盖掉,所以只能利用第一个foreach先将$flag的值赋给$_200,然后利用die($_200)将原本的flag值打印出来。

最终PAYLOAD:

本地复现,所以flag与原题不一样

GET DATA:?_200=flag

POST DATA:flag=aaaaaaaaaaaaaaaaaaaaa

extract覆盖

extract() 该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。

CTF中extract()导致的变量覆盖问题的例题1:

题目源码:

<?php

  $flag = ‘xxx’;

  extract($_GET);

  if (isset($gift)) 
{
      $content = trim(file_get_contents($flag));

      if ($gift == $content) 
    {
          echo ‘hctf{…}’;

    } 
      else 
    {
          echo ‘Oh..’;
    }

  } 
?>

题目分析:

题目使用了extract($_GET)接收了GET请求中的数据,并将键名和键值转换为变量名和变量的值,然后再进行两个if 的条件判断,所以可以使用GET提交参数和值,利用extract()对变量进行覆盖,从而满足各个条件。

解题方法:

GET请求 ?flag=&gift=,extract()会将flag和gift的值覆盖了,将变量的值设置为空或者不存在的文件就满足gift===content。

最终PAYLOAD:

GET DATA: ?flag=&gift=

CTF中extract()导致的变量覆盖问题的例题2:

题目源码:

<?php 
    if ($_SERVER["REQUEST_METHOD"] == “POST”) 
   {
        extract($_POST);
    
        if ($pass == $thepassword_123) 
       { 

            <div class=”alert alert-success”>

            <code><?php echo $theflag; ?></code>

            </div>

        } 
    }
?>

题目分析:

题目要求使用POST提交数据,extract($_POST)会将POST的数据中的键名和键值转换为相应的变量名和变量值,利用这个覆盖$pass和$thepassword_123变量的值,从而满足pass==thepassword_123这个条件。

解题方法:

使用POST请求提交pass=&thepassword_123=, 然后extract()会将接收到的数据将$pass和$thepassword_123变量的值覆盖为空,便满足条件了。

最终PAYLOAD:

POST DATA:pass=&thepassword_123=

parse_str覆盖

parse_str() 函数用于把查询字符串解析到变量中,如果没有array 参数,则由该函数设置的变量将覆盖已存在的同名变量。

语法:parse_str(string,array)

CTF中parse_str()导致的变量覆盖问题的例题1:

题目源码:

<?php

       error_reporting(0);

       if (empty($_GET['id'])) 
      {
            show_source(__FILE__);
            die();
      } 
      else 
     {
            include (‘flag.php’);
            $a = “www.OPENCTF.com 
            $id = $_GET['id'];
            @parse_str($id);
            if ($a[0] != ‘QNKCDZO’ && md5($a[0]) == md5(‘QNKCDZO’)) 
           {
                 echo $flag;
           } 
           else 
           {
                 exit(‘其实很简单其实并不难!’);
           }

       }

?> 

题目分析:

首先要求使用GET提交id参数,然后parse_str($id)对id参数的数据进行处理,再使用判断a[0] != ‘QNKCDZO’ && md5( a[0]) == md5(‘QNKCDZO’)的结果是否为真,为真就返回flag,md5(‘QNKCDZO’)的结果是0e830400451993494058024219903391由于此次要满足a[0] != ‘QNKCDZO’ && md5(a[0]) == md5(‘QNKCDZO’)所以要利用php弱语言特性,0e123会被当做科学计数法,0 * 10 x 123。所以需要找到一个字符串md5后的结果是0e开头后面都是数字的,如,240610708,s878926199a

解题方法:

使用GET请求id=a[0]=240610708,这样会将a[0]的值覆盖为240610708,然后经过md5后得到0e462097431906509019562988736854与md5(‘QNKCDZO’)的结果0e830400451993494058024219903391比较都是0 所以相等,满足条件,得打flag。

最终PAYLOAD:

GET DATA: ?id=a[0]=s878926199a