提交需求
*
*

*
*
*
立即提交
点击”立即提交”,表明我理解并同意 《美创科技隐私条款》

logo

    产品与服务
    解决方案
    技术支持
    合作发展
    关于美创

    申请试用
      变量覆盖漏洞利用及防御方案
      发布时间:2020-03-16 阅读次数: 296 次

      一、漏洞简介


      变量覆盖漏洞是指攻击者使用自定义的变量去覆盖源代码中的变量,从而改变代码逻辑,实现攻击目的的一种漏洞。通常来说,单独的变量覆盖漏洞很难有利用价值,但是在与其他应用代码或漏洞结合后,其造成的危害可能是无法估量的。例如购买商品的支付系统若存在变量覆盖漏洞,就可能存在0元支付下单的情况。


      二、漏洞产生的原因


      变量覆盖漏洞大多数由函数使用不当导致,经常引发变量覆盖漏洞的函数有:

      •   extract()

      •   parse_str()

      •   import_request_variables()

      •   $$(可变变量)

      • register_globals=On (PHP5.4之后正式移除此功能)


      三、漏洞挖掘


      1. extract()函数使用不当导致的变量覆盖

      extract()函数覆盖变量需要一定条件,它的官方说明为“从数组中将变量导入到当前的符号表”,即将数组中的键值对注册成函数,使用数组键名作为变量名,使用数组键值作为变量值。extract()函数的结构如下:

      extract(array,extract_rules,prefix)


      参数

      描述

      array

      必需。规定要使用的数组。

       

      extract_rules

      可选。extract() 函数将检查每个键名是否为合法的变量名,同时也检查和符号表中已存在的变量名是否冲突。对不合法和冲突的键名的处理将根据此参数决定。

      prefix

      可选。请注意 prefix 仅在 extract_type 的值是 EXTR_PREFIX_SAMEEXTR_PREFIX_ALLEXTR_PREFIX_INVALID  EXTR_PREFIX_IF_EXISTS 时需要。如果附加了前缀后的结果不是合法的变量名,将不会导入到符号表中。

      前缀和数组键名之间会自动加上一个下划线。


      从以上说明我们可以看到第一个参数是必须的,会不会导致变量覆盖漏洞由第二个参数决定,该函数有三种情况会覆盖已有变量,分别如下:


      第一种:当第二个参数为EXTR_OVERWRITE 时,它表示如果有冲突,则覆盖已有的变量。


      第二种:当只传入第一个参数,这时候默认为EXTR_OVERWRITE模式。


      第三种:当第二个参数为EXTR_IF_EXISTS 时,它表示仅在当前表中已有同名变量时,覆盖它们的值,其他的都不注册新变量。


      下面我们用代码来说明,测试代码如下:


      测试结果如下:


      原本变量$a的值为1,经过extract()函数对变量$b处理后,变量$a的值被成功覆盖为了3.


      2. parse_str()函数使用不当导致的覆盖

      parse_str()函数的作用是解析字符串并且注册陈变量,它在注册变量之前不会验证当前变量是否已经存在,所以会直接覆盖掉已有的变量。parse_str()函数的结构如下:

      parse_str(string,array)


      参数

      描述

      string

      必需。规定要解析的字符串

      array

      可选。规定存储变量的数组的名称。该参数指示变量将被存储到数组中。


      从以上说明我们可以看到第一个参数是必须的,它代表要解析注册成变量的字符串,形式为“a=1”,经过parse_str()函数之后会注册变量$a并且赋值为1。


      测试代码如下:


      测试结果如下,变量$a原有的值1被覆盖成了5.


      3. import_request_variables()所导致的变量覆盖

      import_request_variables()函数作用是把GET、POST、COOKIE的参数注册成变量,该函数只能用在PHP4.1 ~ PHP5.4之间。


      import_request_variables()函数的结构如下:

      import_request_variables ( string $types , string $prefix )


      其中$type代表要注册的变量,当$type为GPC的时候,则会注册GET、POST、COOKIE参数为变量。


      测试代码如下:


      测试结果如下,变量$a原有的值1被覆盖成了6.

      4. 由$$变量赋值引发的覆盖

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

      从代码中我们可以看出$_key为COOKIE、POST、GET中的参数,$key的值为a而还有一个$在a的前面,结合起来则是$a=addslashes($_value);所以这样会覆盖已有的变量$a的值。在浏览器输入http://127.0.0.1/test.php?a=666,结果如下,可以看到已经成功把变量$a的值由2覆盖成了666。

      5.全局变量的覆盖

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

      当register_globals为OFF时,我们无法将未初始化的变量进行注册,如下图所示:


      当register_global=ON时,可以看到已经成功注册了一个未初始化的变量,如下图所示:

      还有一种情况,通过$GLOBALS获取的变量在使用不当时也会导致变量覆盖,同样漏洞触发的前提是register_globals为ON,如下图所示,已成功通过注入GLOBALS`a`来改变$a的值:


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


      四、漏洞防范


      变量覆盖漏洞最常见的漏洞点是在做变量注册时没有验证变量是否存在,以及在赋值给变量的时候,所以一般推荐使用原始的变量数组,如$_GET、$_POST,或者在注册变量前一定要验证变量是否存在。


      ①使用原始变量

      建议不注册变量,直接用原生的$_GET、$_POST等数组变量进行操作,如果考虑程序可读性等原因,需要注册个别变量,可以直接在代码中定义变量,然后再把请求中的值赋值给他们。


      ②验证变量存在

      如果一定要使用前面几种方式注册变量,为了解决变量覆盖的问题,可以再注册变量前先判断变量是否存在。如使用extract( )函数则可以配置第二个参数为EXTR_SKIP。使用php parse_str函数注册变量前需要先自行通过代码判断变量是否存在。最重要的一点,自行申明的变量一定要初始化,不然即使注册变量代码在执行流程最前面也能覆盖掉这些未初始化的变量。


      免费试用
      服务热线

      马上咨询

      400-811-3777

      回到顶部