变量覆盖漏洞


title: 变量覆盖漏洞

变量覆盖指的是用我们自定义的参数值替换程序原有的变量值,一般变量覆盖漏洞需要结合程序的其它功能来实现完整的攻击。经常导致变量覆盖漏洞场景有:$$,extract()函数,parse_str()函数,import_request_variables()使用不当,开启了全局变量注册等。

常见的变量覆盖

全局变量覆盖

register_globals的意思就是注册为全局变量,所以当On的时候,传递过来的值会被直接的注册为全局变量直接使用,而Off的时候,我们需要到特定的数组里去得到它。

<?php  
//?id=1
echo "Register_globals: ".(int)ini_get("register_globals")."<br/>"; 
echo '$_GET["id"] :'.$_GET['id']."<br/>";
echo '$id :'.$id;
?>

当register_globals=Off的时候,下一个程序接收的时候应该用$_GET[‘id’]来接受传递过来的值;

当register_globals=On的时候,下一个程序可以直接使用id,id来接受值,也可以用id来接受值,也可以用_GET[‘id’]来接受传递过来的值。

tips:如果上面的代码中,已经对变量idid赋了初始值,比如id赋了初始值,比如id=0,那么即使在URL中有/test.php?id=1,也不会将变量覆盖,id值为0

<?php  
echo "Register_globals: ".(int)ini_get("register_globals")."<br/>"; 
if (ini_get('register_globals')) foreach($_REQUEST as $k=>$v) unset(${$k});  
print $a."<br/>";  
print $_GET[b];  
?> 

在register_globals=ON时,

提交/test.php?a=1&b=2 , 变量a,a未初始化,a未初始化,_GET[b]=2

提交/test.php??GLOBALS[a]=1&b=2,a=1,a=1,a=1,_GET[b]=2

tips: 从 PHP » 4.2.0 版开始配置文件中 PHP 指令 register_globals 的默认值从 on 改为 off 了,自 PHP 5.3.0 起废弃并将自 PHP 5.4.0 起移除。

$$导致的变量覆盖

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

<?php
foreach (array('_COOKIE','_POST','_GET') as $_request)  
{
    foreach ($$_request as $_key=>$_value)  
    {
        $$_key=  $_value;
    }
}
$id = isset($id) ? $id : 2;
if($id == 1) {
    echo "flag{xxxxxxxxxx}";
    die();
}
echo $id;
?>

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 是必需的。
该参数规定了前缀。前缀和数组键名之间会自动加上一个下划线。

代码示例:将键值 “Cat”、“Dog” 和 “Horse” 赋值给变量 aa、a、b 和 $c

<?php
$a = "Original";
$my_array = array("a" => "Cat","b" => "Dog", "c" => "Horse");
extract($my_array);
echo "\$a = $a; \$b = $b; \$c = $c";
?>
//运行结果:$a = Cat; $b = Dog; $c = Horse
<?php
$id=1;  
extract($_GET);
echo $id;
?>
//提交:?id=123
//结果: 123

tips: 在调用extract()时使用EXTR_SKIP保证已有变量不会被覆盖 extract($_GET,EXTR_SKIP);

parse_str()变量覆盖

parse_str()函数把查询字符串解析到变量中,并且不会验证当前变量是否已经存在。
语法
parse_str(string,array)
参数 描述
string必需。 规定要解析的字符串。
array可选。 规定存储变量的数组名称。该参数指示变量存储到数组中

如果未设置 array 参数,由该函数设置的变量将覆盖已存在的同名变量。
php.ini 文件中的 magic_quotes_gpc 设置影响该函数的输出。如果已启用,那么在 parse_str() 解析之前,变量会被 addslashes() 转换。parse_str函数的作用就是解析字符串并注册成变量,在注册变量之前不会验证当前变量是否存在,所以直接覆盖掉已有变量

<?php
parse_str("a=1");
echo $a."<br/>";      //$a=1
parse_str("b=1&c=2",$myArray);
print_r($myArray);   //Array ( [c] => 1 [b] => 2 ) 
?>

import_request_variables()变量覆盖

import_request_variables—将 GET/POST/Cookie 变量导入到全局作用域中import_request_variables()函数就是把GET、POST、COOKIE的参数注册成变量,用在register_globals被禁止的时候
语法
import_request_variables(stringtypes[,stringtypes[,stringtypes[,stringprefix] )
$type代表要注册的变量,G代表GET,P代表POST,C代表COOKIE,第二个参数为要注册变量的前缀

<?php
$auth='0';
import_request_variables('G');
if($auth== 1){
echo"private!";
}else{
echo"public!";
}
?>

get auth=1时,网页上会输出private!import_request_variables(‘G’)指定导入GET请求中的变量,从而导致变量覆盖。

靶场实践

靶场环境:DuomiCmsX2.0
使用工具:seay源码审计系统
我们可以使用seay代码审计工具去快速寻找到危险函数,这里我可以添加一个关于$$ 变量覆盖的正则匹配规则。

([^\$"]|$)\$\{?\$

变量覆盖漏洞
然后自动审计一下可能存在的漏洞
变量覆盖漏洞
最后经过寻找,在这里发现了foeach和$![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly90dmExLnNpbmFpbWcuY24vbGFyZ2UvMDA3ckF5OWhneTFnMnF5ZzJ0d2lqajMxZnAwYjAweXAuanBn?xossprocess=image/format,png)![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly90dmExLnNpbmFpbWcuY24vbGFyZ2UvMDA3ckF5OWhneTFnMnF5bWg3aWw3ajMxMGwwa20wd3AuanBn?xossprocess=image/format,png)![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly90dmExLnNpbmFpbWcuY24vbGFyZ2UvMDA3ckF5OWhneTFnMnF5dmJ1OWowajMxaGMwc20xNGsuanBn?xossprocess=image/format,png)login.php,common.phpcheck.admin.php![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly90dmExLnNpbmFpbWcuY24vbGFyZ2UvMDA3ckF5OWhneTFnMnF5eno5ODN0ajMxaGMwc21uOHEuanBn?xossprocess=image/format,png)check.admin.phpsessionadmin.manager.php![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly90dmExLnNpbmFpbWcuY24vbGFyZ2UvMDA3ckF5OWhneTFnMnF6Mnh2cWxiajMxaGMwc213bnguanBn?xossprocess=image/format,png)的变量覆盖 ![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly90dmExLnNpbmFpbWcuY24vbGFyZ2UvMDA3ckF5OWhneTFnMnF5ZzJ0d2lqajMxZnAwYjAweXAuanBn?x-oss-process=image/format,png) ![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly90dmExLnNpbmFpbWcuY24vbGFyZ2UvMDA3ckF5OWhneTFnMnF5bWg3aWw3ajMxMGwwa20wd3AuanBn?x-oss-process=image/format,png) 看了一下,也就看到了一个危险函数,和一些传参,然后我们看一下有没有哪个文件调用了这个文件。 ![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly90dmExLnNpbmFpbWcuY24vbGFyZ2UvMDA3ckF5OWhneTFnMnF5dmJ1OWowajMxaGMwc20xNGsuanBn?x-oss-process=image/format,png) 我们找到login.php,发现它调用了common.php和check.admin.php ![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly90dmExLnNpbmFpbWcuY24vbGFyZ2UvMDA3ckF5OWhneTFnMnF5eno5ODN0ajMxaGMwc21uOHEuanBn?x-oss-process=image/format,png) 而我们发现check.admin.php好像通过获取用户登录时的session来判断了用户的权限,而在admin.manager.php中有一个这样的判断 ![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly90dmExLnNpbmFpbWcuY24vbGFyZ2UvMDA3ckF5OWhneTFnMnF6Mnh2cWxiajMxaGMwc213bnguanBn?x-oss-process=image/format,png) 直接根据判断用户传进来的的变量覆盖![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly90dmExLnNpbmFpbWcuY24vbGFyZ2UvMDA3ckF5OWhneTFnMnF5ZzJ0d2lqajMxZnAwYjAweXAuanBn?x−oss−process=image/format,png)![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly90dmExLnNpbmFpbWcuY24vbGFyZ2UvMDA3ckF5OWhneTFnMnF5bWg3aWw3ajMxMGwwa20wd3AuanBn?x−oss−process=image/format,png)看了一下,也就看到了一个危险函数,和一些传参,然后我们看一下有没有哪个文件调用了这个文件。![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly90dmExLnNpbmFpbWcuY24vbGFyZ2UvMDA3ckF5OWhneTFnMnF5dmJ1OWowajMxaGMwc20xNGsuanBn?x−oss−process=image/format,png)我们找到login.php,发现它调用了common.php和check.admin.php![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly90dmExLnNpbmFpbWcuY24vbGFyZ2UvMDA3ckF5OWhneTFnMnF5eno5ODN0ajMxaGMwc21uOHEuanBn?x−oss−process=image/format,png)而我们发现check.admin.php好像通过获取用户登录时的session来判断了用户的权限,而在admin.manager.php中有一个这样的判断![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly90dmExLnNpbmFpbWcuY24vbGFyZ2UvMDA3ckF5OWhneTFnMnF6Mnh2cWxiajMxaGMwc213bnguanBn?x−oss−process=image/format,png)直接根据判断用户传进来的groupid进行身份验证。而这三个session真实的名字叫做这样的
变量覆盖漏洞
根据之前commo.php的文件中有session的变量覆盖漏洞,我们可以通过构造POC使得duomi_group_id=1,就可以登录系统管理员,POC如下:

interface/comment.php?_SESSION[duomi_group_id]=1&_SESSION[duomi_admin_id]=1&_SESSION[duomi_admin_name]=admin

变量覆盖漏洞
就是在这里给服务器传session值
变量覆盖漏洞
报错,然后退回去看一下
变量覆盖漏洞
很明显,成功登录管理员,进入后台。

上一篇:mac 设置alias别名保存永久生效


下一篇:iTerm2 + Oh My Zsh