Web安全领域的探索之变量覆盖漏洞

「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」。

什么是变量覆盖

变量覆盖指的是可以用我们的传参值替换程序原有的变量值
复制代码

漏洞成因

  • extract()函数使用不当
  • parse_str()使用不当
  • import_request_variables() 开启了全局变量注册等

1. $$就是将之前定义的变量的值重新定义新的变量

<?php
$a='aaa';
$aaa='lin92n';
echo $$a; 
//解析过程: $$a=$($a)=$(aaa)='lin92n'
?>
复制代码

以上结果输出显示lin92n

2. extract()函数使用不当

  • 定义和用法

extract() 函数从数组中将变量导入到当前的符号表。

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

第二个参数 type 用于指定当某个变量已经存在,而数组中又有同名元素时,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 可选。请注意 prefix 仅在 extract_type 的值是 EXTR_PREFIX_SAME,EXTR_PREFIX_ALL,EXTR_PREFIX_INVALID 或 EXTR_PREFIX_IF_EXISTS 时需要。如果附加了前缀后的结果不是合法的变量名,将不会导入到符号表中。 前缀和数组键名之间会自动加上一个下划线。
  • 技术细节
返回值: 返回成功导入到符号表中的变量数目。
PHP 版本: 4+
更新日志: extract_rules 的值 EXTR_REFS 是在 PHP 4.3 中新增的。 extract_rules 的值 EXTR_IF_EXISTS 和 EXTR_PREFIX_IF_EXISTS 是在 PHP 4.2 中新增的。 自 PHP 4.0.5 起,该函数返回成功导入到符号表中的变量数目。 extract_rules 的值 EXTR_PREFIX_INVALID 是在 PHP 4.0.5 中新增的。 自 PHP 4.0.5 起,extract_rules 的值 EXTR_PREFIX_ALL 也包含数字变量。
  • 案例
<!DOCTYPE html>
<html>
<body>
<?php
$a = "Original";
$my_array = array("a" => "Cat","b" => "Dog", "c" => "Horse");
extract($my_array);
echo "$a = $a; $b = $b; $c = $c";
?>
</body>
</html>
复制代码
  • 结果
$a = Cat; $b = Dog; $c = Horse 
复制代码

3. parse_str()使用不当

  • 定义和用法

parse_str() 函数把查询字符串解析到变量中。

注释:如果未设置 array 参数,则由该函数设置的变量将覆盖已存在的同名变量。

注释:php.ini 文件中的 magic_quotes_gpc 设置影响该函数的输出。如果已启用,那么在 parse_str() 解析之前,变量会被 addslashes() 转换。

  • 语法
parse_str(string,array)
复制代码
参数 描述
string 必需。规定要解析的字符串。
array 可选。规定存储变量的数组的名称。该参数指示变量将被存储到数组中。
  • 案例
<!DOCTYPE html>
<html>
<body>
<?php
parse_str("name=Bill&age=60",$myArray);
print_r($myArray);
?>
</body>
</html>
复制代码
  • 结果
Array ([name] => Bill [age] => 60) 
复制代码
  • 技术细节
返回值: 无返回值。
PHP 版本: 4+
更新日志: 在 PHP 4.0.3 中,新增了 array 参数。

4. import_request_variables('GP')

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
复制代码

语法

bool import_request_variables ( string $types [, string $prefix ] )
复制代码

参数说明:

  • $types:指定需要导入的变量,可以用字母 G、P 和 C 分别表示 GET、POST 和 Cookie,这些字母不区分大小写,所以你可以使用 g 、 p 和 c 的任何组合。POST 包含了通过 POST 方法上传的文件信息。注意这些字母的顺序,当使用 gp 时,POST 变量将使用相同的名字覆盖 GET 变量。任何 GPC 以外的字母都将被忽略。
  • ** p r e f i x :变量名的前缀,置于所有被导入到全局作用域的变量之前。所以如果你有个名为 u s e r i d G E T 变量,同时提供了 p r e f 为前缀,那么你将获得一个名为 prefix**: 变量名的前缀,置于所有被导入到全局作用域的变量之前。所以如果你有个名为 userid 的 GET 变量,同时提供了 pref_ 作为前缀,那么你将获得一个名为 ` pref_userid的全局变量。虽然 prefix 参数是可选的,但如果不指定前缀,或者指定一个空字符串作为前缀,你将获得一个E_NOTICE` 级别的错误。

修复方案

  1. 在php.ini文件中设置register_globals=OFF
  2. 使用原始变量数组,如$_POST,$_GET等数组变量进行操作
  3. 不使用foreach语句来遍历$_GET变量,而改用[(index)]来指定
  4. 验证变量是否存在,注册变量前先判断变量是否存在

Guess you like

Origin juejin.im/post/7069652291703275556