php变量覆盖

web 专栏收录该内容
32 篇文章 0 订阅

前言

变量覆盖指的是用我们自定义的参数值替换程序原有的变量值,一般变量覆盖漏洞需要结合程序的其它功能来实现完整的攻击。

经常导致变量覆盖漏洞场景有:$$,extract()函数,parse_str()函数等.

正文

$$ 变量覆盖的问题

简介

在PHP中$$表示的是一个可变变量获取了一个普通变量的值作为这个可变变量的变量名。

<?php
$c='hello';
$$c='world';
echo $c;
echo $$c;
?>

在这个例子中,是变量标识符,c是变量名,而下面的变量是变量标识符,c是变量名,而下面的变量c,是把c,是把c当成了当成了变量名的一个变量,上面的输出结果是:

helloworld // c = h e l l o 而 c=hello 而 c=hello$c=world

漏洞产生

使用foreach来遍历数组中的值,然后再将获取到的数组键名作为变量,数组中的键值作为变量的值。因此就产生了变量覆盖漏洞。

<?php
$ary=array('a','b','c','c','e');
foreach($ary as $key=>$value){     //$ary的键名赋给$key,键值赋给$value
	$$key=$value;    //把键值赋给$$key
}
print_r($key);      //输出4
print_r($value);    //输出e
print_r($$key);      //输出e
?>

结果输出4ee
在这里插入图片描述
换成 G E T 和 _GET和 GET_POST是一样的

<?php
$id=5;
foreach ($_GET as $key => $value) {
$$key = $value;
}
echo $a;
?>

如果get传的是?id=1,那么,经过**$ k e y = v a l u e ∗ ∗ 之 后 , 就 会 变 成 ‘ v a l u e ∗ ∗ 之 后 , 就 会 变 成 ‘ i d = 1 , 覆 盖 掉 原 来 的 key = value∗∗之后,就会变成‘value∗∗之后,就会变成‘id=1,覆盖掉原来的 key=valuevalueid=1id=5`.

在这里插入图片描述

漏洞复现

一道ctf题目

<?php
include "flag.php";                                               
$_403 = "AccessDenied";
$_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);
else
{
    echo "This is your flag : ". $flag . "\n";
    die($_200);
}
?>

从源码文件中可以看出,要想获得flag,你必须知道原来的flag,那是不可能的,
这个时候我们就可以利用变量覆盖漏洞。

foreach ($_GET as $key => $value)
	$$key = $$value

key=value的处理后,就会变为_200=_200=flag,这样就会将原来的200的值覆盖掉,换成

2​00的值覆盖掉,换成flag的值。

foreach ($_POST as $key => $value)
$$key = $value;

post方法传入flag=abc,则处理后变成$flag=abc。这样就造成将我们需要获取的flag的值给覆盖掉了。不过,当通过get传入_200=flag之后,flag的值将会赋给_200,这时候随便post什么都可以,反正flag已经在_200=flag里面了。

get:_200=flag
post:flag=hahaha

在这里插入图片描述 ok 成功了

extract()函数

定义和用法

extract() 函数从数组中将变量导入到当前的符号表。该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。该函数返回成功设置的变量数目。具体信息

语法

   extract(array,extract_rules,prefix)
参数描述
array必需。规定要使用的数组。
extract_rules可选。extract() 函数将检查每个键名是否为合法的变量名,同时也检查和符号表中已存在的变量名是否冲突。对不合法和冲突的键名的处理将根据此参数决定。可能的值: EXTR_OVERWRITE - 默认。如果有冲突,则覆盖已有的变量。 EXTR_SKIP - 如果有冲突,不覆盖已有的变量。 EXTR_PREFIX_SAME - 如果有冲突,在变量名前加上前缀 prefix。 EXTR_PREFIX_ALL - 给所有变量名加上前缀 prefix。 EXTR_PREFIX_INVALID - 仅在不合法或数字变量名前加上前缀 prefix。 EXTR_IF_EXISTS - 仅在当前符号表中已有同名变量时,覆盖它们的值。其它的都不处理。 EXTR_PREFIX_IF_EXISTS - 仅在当前符号表中已有同名变量时,建立附加了前缀的变量名,其它的都不处理。 EXTR_REFS - 将变量作为引用提取。导入的变量仍然引用了数组参数的值。
prefix可选。如果 extract_rules 参数的值是 EXTR_PREFIX_SAME、EXTR_PREFIX_ALL、 EXTR_PREFIX_INVALID 或 EXTR_PREFIX_IF_EXISTS,则 prefix 是必需的。 该参数规定了前缀。前缀和数组键名之间会自动加上一个下划线。

例如:

<?php
$a = "Original";
$my_array = array("a" => "Cat","b" => "Dog", "c" => "Horse");
extract($my_array);
echo "\$a = $a; \$b = $b; \$c = $c";
?>

漏洞复现

<?php
include('flag.php');

echo $test;
extract($_GET);
if(isset($gift)){
    $content=trim($test);
    if($gift==$content){
        
        echo 'flag is '.$flag;
    }
    else{
    echo 'error';
}
}

变量content的值是通过读取变量test的值获取到的。如果两个变量相等输出flag。如果不相等,输出错误。但是我们并不知道test的值是什么?所以我们使用变量覆盖漏洞,重新给test赋值。

例如:GET[‘test’]=’a’,被extract()函数处理后,就变成了
G​ET[‘test’]=’a’,被extract()函数处理后,就变成了test=’a’
构造我们的payload:

Get方法传值:?gift=a&test=a.

在这里插入图片描述

Parse_str()

分析

Parse_str()将字符串解析成多个变量
注释:

parse_str(string,array)
如果未设置 array 参数,由该函数设置的变量将覆盖已存在的同名变量。
php.ini 文件中的 magic_quotes_gpc 设置影响该函数的输出。如果已启用,那么在 parse_str() 解析之前,变量会被 addslashes() 转换。

例子:

<?php
parse_str("name=Bill&age=60");
echo $name."<br>";
echo $age;
?>

输出:
Bill
60

在这里插入图片描述

漏洞复现

<?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);//把查询字符串解析到变量中,没有使用array选项,若有同名变量,将原来的覆盖。这里明显将原来的$a的值给覆盖掉。
	if($a[0]!='QNKCDZO'&&md5($a[0])==md5('QNKCDZO')){
		//判断$a[0]的值不是QNKCDZO并且$a[0]的MD5值要和QNKCDZO的MD5值相同,很难找出这样的字符串。
        echo $flag;
	}else{
		exit('其实很简单,其实并不难');
	}
}

这里最重要的就是处理if(KaTeX parse error: Expected 'EOF', got '&' at position 16: a[0]!='QNKCDZO'&̲&md5(a[0])==md5(‘QNKCDZO’))这个问题,我们要找到一个字符串值和QNKCDZO不同,但是字符串的MD5值和QNKCDZO的MD5值相同。

这里要利用PHP处理0e开头的MD5哈希字符串的漏洞,PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0,这样的话两个不同字符串也就可以相等了,都等于0就行。以0e开头的这样的

而QNKCDZO的MD5加密后的值是0e830400451993494058024219903391,所以再找一个字符串,值和QNKCDZO不要,但MD5加密后的值是0e开头的字符串就行

构造payload:

?id=a[]=s1836677006a

在这里插入图片描述参考文章:https://blog.csdn.net/qq_41381461/article/details/90047616?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

  • 0
    点赞
  • 0
    评论
  • 4
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 像素格子 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值