浙江省委宣传部副部长、省委网信办主任赵磊:守正创新 辩证施策 全力推动网络生态治理工作迈上新台阶
2026-02-10
美创产品全面入围中直机关2025年网络设备框架协议采购项目
2026-02-04
连续5年!美创再获中国网络安全产业联盟“先进会员单位”表彰
2026-01-21
每周安全速递³⁷¹ | 勒索软件攻击导致心理健康机构超11万人数据泄露
2026-01-06
四年同行,韧性共铸:西南某商行携手美创科技再度通过年度容灾大考
2025-12-26
存储域
数据库加密 诺亚防勒索访问域
数据库防水坝 数据库防火墙 数据库安全审计 动态脱敏流动域
静态脱敏 数据水印 API审计 API防控 医疗防统方运维服务
数据库运维服务 中间件运维服务 国产信创改造服务 驻场运维服务 供数服务安全咨询服务
数据出境安全治理服务 数据安全能力评估认证服务 数据安全风险评估服务 数据安全治理咨询服务 数据分类分级咨询服务 个人信息风险评估服务 数据安全检查服务
变量覆盖漏洞是指攻击者使用自定义的变量去覆盖源代码中的变量,从而改变代码逻辑,实现攻击目的的一种漏洞。通常来说,单独的变量覆盖漏洞很难有利用价值,但是在与其他应用代码或漏洞结合后,其造成的危害可能是无法估量的。例如购买商品的支付系统若存在变量覆盖漏洞,就可能存在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_SAME,EXTR_PREFIX_ALL,EXTR_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函数注册变量前需要先自行通过代码判断变量是否存在。最重要的一点,自行申明的变量一定要初始化,不然即使注册变量代码在执行流程最前面也能覆盖掉这些未初始化的变量。