欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

PHP代码审计:变量覆盖

程序员文章站 2022-05-14 23:46:45
...

0x00 前提

本文是给作为给小伙伴分享教学的一篇文章,给讲一下,所以写的比较简陋。。。见谅而且都比较基础,只是简单讲课提纲吧

0x01 变量覆盖审计

0x00 简介

变量覆盖,顾名思义就是可以覆盖已有变量值,导致变量覆盖的漏洞

常见的造成的代码审计的情景是代码中出现以下关键词:

  • register_globals=on
  • extract()函数
  • parse_str()函数
  • import_request_variables()函数
  • $$

0x01 变量覆盖演示

extract()

extract(array,extract_rules,prefix)函数

https://www.runoob.com/php/func-array-extract.html

该函数可以从数组中将变量导入到当前的符号表,即将数组中的键值对注册成函数,使用数组键名作为变量名,使用数组键值作为变量值。

这里我们要注意一下该函数的第二个参数

  • EXTR_OVERWRITE - 默认。如果有冲突,则覆盖已有的变量。
  • EXTR_SKIP - 如果有冲突,不覆盖已有的变量。

这就为我们提供了覆盖的可能。

<?php
$a = 'a';
echo $a.'</br>';
extract($_GET);
echo $a
?>

可以看到我们初始变量值为a但是覆盖之后就变成了我们输入的值。

http://127.0.0.1/test/extract.php?a=123

PHP代码审计:变量覆盖

修复:

在使用extract()函数时,可以指定将第二个参数设置为EXTRS_KIP

parse_str()

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

在没有array参数的情况下使用此函数,

并且在PHP 7.2中将废弃不设置参数的行为,此函数没有返回值。

<?php
$a = "giao";
echo "a:" . $a;
echo "<br>";
$b = $_GET['b'];
parse_str($b);
echo "a_2:" . $a;
?>
http://127.0.0.1/test/parse_str.php?b=a=zeo

PHP代码审计:变量覆盖

$$

典型的例子就是foreach来遍历数组中的值作为变量。

$$是一种可变变量的写法,它可以使一个普通变量的值作为可变变量的名字,这种类型常常会使用遍历的方式来释放变量的代码

<?php
$a = 10;
echo $a;
echo "<br>";
foreach ($_POST as $k => $v){
    $$k = $v;
    echo $a;
}
?>

PHP代码审计:变量覆盖

import_request_variables()

import_request_variables ( string $types , string $prefix )

https://www.runoob.com/php/php-import_request_variables-function.html

import_request_variables() 函数将 GET/POST/Cookie 变量导入到全局作用域中。该函数在最新版本的 PHP 中已经不支持。

import_request_variables() 函数将 GET/POST/Cookie 变量导入到全局作用域中。如果你禁止了 register_globals,但又想用到一些全局变量,那么此函数就很有用。

版本要求:PHP 4 >= 4.1.0, PHP 5 < 5.4.0

第二个参数$types:指定需要导入的变量,可以用字母 G、P 和 C 分别表示 GET、POST 和 Cookie,这些字母不区分大小写,所以你可以使用 g 、 p 和 c 的任何组合。POST 包含了通过 POST 方法上传的文件信息。注意这些字母的顺序,当使用 gp 时,POST 变量将使用相同的名字覆盖 GET 变量。任何 GPC 以外的字母都将被忽略。

PHP代码审计:变量覆盖

全局变量

当你在升级PHP到PHP5.4及之后的版本的时候,是否发现register_global配置指令不再生效了呢

因为从PHP5.4开始register_global配置指令被移除了。

<?php
echo "register_globals: " . (int)ini_get("register_globals");
echo '<br>';
echo "a=" . $a;
?>

PHP代码审计:变量覆盖

0x02 深x服edr实例

简化后的代码

<?php
#var_dump($_REQUEST);


$show_form = function($params) use(&$strip_slashes, &$show_input) {
    extract($params);

    $host  = isset($host)  ? $strip_slashes($host)  : "127.0.0.1";
    $path  = isset($path)  ? $strip_slashes($path)  : "";
    $row   = isset($row)   ? $strip_slashes($row)   : "";
    $limit = isset($limit) ? $strip_slashes($limit) : 1000;

    // 绘制表单
    echo "<pre>";
    echo '<form id="studio" name="studio" method="post" action="">';
    $show_input(array("title" => "Host ",  "name" => "host",  "value" => $host,  "note" => " - host, e.g. 127.0.0.1"));
    $show_input(array("title" => "Path ",  "name" => "path",  "value" => $path,  "note" => " - path regex, e.g. mapreduce"));
    $show_input(array("title" => "Row  ",  "name" => "row",   "value" => $row,   "note" => " - row regex, e.g. \s[w|e]\s"));
    $show_input(array("title" => "Limit",  "name" => "limit", "value" => $limit, "note" => " - top n, e.g. 100"));
    echo '<input type="submit" id="button">';
    echo '</form>';
    echo "</pre>";
};

$show_form($_REQUEST);

?>

变量匿名函数 $show_form 具有一个形式参数 $params

在这里也就是array(“strip_slashes”=>“system”,“host”=>“id”);

接下来执行extract($params);,后进入如下代码:

$host  = isset($host)  ? $strip_slashes($host)  : "127.0.0.1";

在这个过程中就产生了漏洞,想要了解具体原因:

首先函数传入参数值为array("strip_slashes"=>"system","host"=>"id");

经过extract()函数后,赋值了2个变量:

$strip_slashes = 'system';
$host = 'id';

变量$host利用三元运算重新赋值$strip_slashes($host)

而实际上其赋值内容是函数system('id')的返回结果,这也就造成了命令执行漏洞。

0x03MetInfo实例

/include/common.inc.php

传入的cookie、get、post参数进行变量赋值

foreach(array('_COOKIE', '_POST', '_GET') as $_request) {
	foreach($$_request as $_key => $_value) {
		$_key{0} != '_' && $$_key = daddslashes($_value);
	}
}

daddslashes()防注入,不过并不影响

随便来到一个子文件看看他的加载方式\about\index.php

<?php
# MetInfo Enterprise Content Management System 
# Copyright (C) MetInfo Co.,Ltd (http://www.metinfo.cn). All rights reserved. 
$filpy = basename(dirname(__FILE__));
$fmodule=1;
require_once '../include/module.php';
require_once $module;
# This program is an open source system, commercial use, please consciously to purchase commercial license.
# Copyright (C) MetInfo Co., Ltd. (http://www.metinfo.cn). All rights reserved.
?>

这里使用了require_once函数包含了/include/module.php文件,可以发现这个文件又包含了common.inc.php文件

出现了两个未知变量:$module$fmodule。我们可以用$fmodule变量通过两次文件包含,使用$_request来获取GET传递的新$fmodule值实现变量覆盖。

相关标签: 代码审计