日常记录,仅供收藏,用时不慌。
0x01 漏洞描述
变量覆盖是指可以用自定义的参数值替换程序原有的变量值。该漏洞通常需要结合程序的其他功能来实现完整攻击,比如原本一个文件上传页面,限制的文件扩展名白名单列表写在配置文件中变量中,但是在上传的过程中有一个变量覆盖漏洞可以覆盖掉原来的白名单列表,那就可以覆盖进去一个PHP的扩展名,从而上传一个PHP的shell。
0x02 审计要点
目前变量覆盖漏洞多都是由于函数使用不正确导致的,这些函数有extract()、parse_str()以及import_request_variables()。
-
extract函数
extract()函数为“从数组中将变量导入到当前的符号表”,通俗讲就是将数组中的键值对注册成变量,函数结构如下:
extract(array,extract_rules,prefix)
最多三个参数,三个参数的作用:
其中,第一个参数是必须的,是否导致变量覆盖漏洞由第二个参数决定。有如下三种情况会产生漏洞:
一:只传入一个参数时,默认为EXTR_OVERWRITE模式,表示如果有冲突,则覆盖已有的变量;
二:第二个参数为EXTR_OVERWRITE时;
三:第二个参数为EXTR_IF_EXISTS时,表示仅在当前符号表中已有同名变量时,覆盖它们的值,其它的都不处理。
-
parse_str()函数
parse_str()函数的作用是解析字符串并且注册成变量,它在注册变量之前不会验证当前变量是否已经存在,所以会直接覆盖掉已有变量。
parse_str()函数有两个参数,函数说明如下:
parse_str(string,array)
第一个参数是必需的,代表要解析注册成变量的字符串。第二个参数是一个数组,当其存在时,注册的变量会放到这个数组里,但是如果数组原来就存在相同的键,则会覆盖掉原来的键值。
-
import_request_variables()函数
import_request_variables()函数把GET、POST、Cookie变量导入到全局作用域中,用在register_globals被禁止时,版本需要PHP 4 >= 4.1.0和 PHP 5 < 5.4.0。
import_request_variables()函数语法为:
bool import_request_variables ( string $types [, string $prefix ] )
types 参数指定需要导入的变量。可以用字母‘G’、‘P’和‘C’分别表示 GET、POST 和 Cookie。这些字母不区分大小写,所以你可以使用‘g’、‘p’和‘c’的任何组合。prefix 参数作为变量名的前缀,置于所有被导入到全局作用域的变量之前。
-
$$变量覆盖:
当$_key为COOKIE、POST、GET中的参数,比如提交?a=1,则$key的值为a,而还有一个$在a的前面,结合起来则是$a=addslashes($_value);所以会覆盖已有的变量$a的值。
0x03 典型漏洞代码
变量覆盖核心的代码如下:
在这段代码之前的变量,我们都可以覆盖掉,包括数据库配置,可以看到下面有一个SQL语句中使用了$tablepre变量:
这里我们只要覆盖这个变量即可进行SQL注入。举例一个exp为:
/include/common.inc.php?tablepre=mysql.user limit 1 %23
0x04 防御方案
变量覆盖漏洞最常见漏洞点是在做变量注册时没有验证变量是否存在,以及在赋值给变量的时候,所以我们推荐使用原始的变量数组,如$_GET、$_POST,或者在注册变量前一定要验证变量是否存在。
-
1.使用原始变量
以上变量覆盖漏洞都是因为在进行变量注册而导致,所以要解决变量覆盖的问题,最直接的方法就是不进行变量注册,建议直接用原生的$_GET、$_POST等数组变量进行操作,如果考虑程序可读性等原因,需要注册个别变量,可以直接在代码中定义变量,然后再把请求中的值赋值给它。
-
2.验证变量存在
如果一定要使用前面几种方式注册变量,为了解决变量覆盖的问题,可以在注册变量前先判断变量是否存在,如使用extract()函数则可以配置第二个参数为EXTR_SKIP。使用parse_str()函数注册变量前需要先自行通过代码判断变量是否存在。不建议使用import_request_variables()函数注册全局变量,会导致变量不可控。最重要的一点,自行申明的变量一定要初始化,不然即使注册变量代码在执行流程最前面也能覆盖掉这些未初始化的变量。
点赞,转发,在看
点击关注
学习技术
反入侵实验室
原文始发于微信公众号(反入侵实验室):0基础入门代码审计-9 变量覆盖
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论