PHP代码审计 12 覆盖变量漏洞

本文记录 PHP 代码审计的学习过程,教程为暗月 2015 版的 PHP 代码审计课程

PHP 代码审计博客目录

1. 简介

  1. 产生原因

    1. 是 register_globals 为on 的情况,PHP4 默认开启,PHP5 以后默认关闭。

      从 PHP > 4.2.0 版开始配置文件中 PHP 指令 register_globals 的默认值从 on 改为 off 了,自 PHP 5.3.0 起废弃并将自 PHP 5.4.0 起移除。源自    http://php.net/manual/zh/security.globals.php

    2. 是人为注册成为全局变量

      经常导致变量覆盖漏洞场景有:$$,extract()函数,parse_str()函数,import_request_variables()使用不当

  2. 全局变量的取值与赋值简介

    <?php
    echo $a='a';
    echo "<hr>";
    echo $GLOBAL['a']='b'; 
    echo "<hr>";
    echo $a;
    ?>
    

2. 测试

  1. register_globals 为on 的情况

    已废止,环境未搭建成功

  2. $$导致的变量覆盖问题

    使用foreach来遍历数组中的值,然后再将获取到的数组键名作为变量,数组中的键值作为变量的值。因此就产生了变量覆盖漏洞。请求?id=1 会将 i d 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;
    ?>
    

    浏览器执行 http://127.0.0.1/test.php?id=1

    小记:在代码审计时需要注意类似“$$k”的变量赋值方式有可能覆盖已有的变量,从而导致一些不可控制的结果。

  3. extract()变量覆盖

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

    extract() 官方文档

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

    1. 示例一:

      将键值 “Cat”、”Dog” 和 “Horse” 赋值给变量 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";
      ?>
      

      浏览器执行 http://127.0.0.1/test.php

    2. 示例二:

      <?php
      $id=1;  
      extract($_GET);
      echo $id;
      ?>
      

      浏览器执行 http://127.0.0.1/test.php?id=123

    小记:PHP extract() 函数从数组中把变量导入到当前的符号表中。对于数组中的每个元素,键名用于变量名,键值用于变量值。

  4. parse_str()变量覆盖

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

    parse_str() 官方文档

    tips:parse_str()类似的函数还有mb_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 ) 
    ?>
    

    浏览器执行 http://127.0.0.1/test.php

    与parse_str()类似的函数还有mb_parse_str()

    小记:parse_str — 将字符串解析成多个变量,如果参数str是URL传递入的查询字符串(query string),则将它解析为变量并设置到当前作用域。

  5. import_request_variables变量覆盖

    import_request_variables 函数可以在 register_global = off 时,把 GET/POST/Cookie 变量导入全局作用域中。

    <?php
    import_request_variables("g", "get_");
    echo $get_id;
    ?>
    

    http://127.0.0.1/test.php?id=111

    结果显示 111

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

猜你喜欢

转载自blog.csdn.net/kevinhanser/article/details/81146092