0x00 前言
昨天发的文件包含漏洞和今天的变量覆盖漏洞其实都是属于PHP安全问题的范畴,当然关于PHP安全的问题还有很多,比如后面会总结的代码执行漏洞这些
这个漏洞感觉现在只会在CTF题目中出现,因为防御这个漏洞的方法比较简单
本学习笔记,大量参考自网络上各位大佬总结好的,再加上自己的心得总结而成,用途仅用于安全技术学习.文末注明参考资料,侵删.
0x01 基础知识
既然是PHP安全问题,那么就肯定和php的一些函数有关,下面来看看学习这些函数
全局变量
最常用的就是$GLOBALS
作用是引用全局作用域中可用的全部变量
说明: 一个包含了全部变量的全局组合数组。变量的名字就是数组的键。
extract()
https://www.runoob.com/php/func-array-extract.html
定义:
extract() 函数从数组中将变量导入到当前的符号表。
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
该函数返回成功设置的变量数目。
语法:
1 | 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 | 可选。如果 extract_rules 参数的值是 EXTR_PREFIX_SAME、EXTR_PREFIX_ALL、 EXTR_PREFIX_INVALID 或 EXTR_PREFIX_IF_EXISTS,则 prefix 是必需的。 该参数规定了前缀。前缀和数组键名之间会自动加上一个下划线。 |
parse_str()
官方解释为: 将字符串解析成多个变量,该函数没有返回值
parse_str() 函数把查询字符串解析到变量中。
注释:如果未设置 array 参数,由该函数设置的变量将覆盖已存在的同名变量。
注释:php.ini 文件中的 magic_quotes_gpc 设置影响该函数的输出。如果已启用,那么在 parse_str() 解析之前,变量会被 addslashes() 转换。
import_request_variables()
其中第二个参数是为导入的变量添加的前缀,如果没有指定,则将覆盖全局变量
可变变量$$
0x02 变量覆盖漏洞
变量覆盖指的是可以用我们自定义的参数值替换程序原有的变量值,变量覆盖漏洞通常需要结合程序的其他功能来实现完整攻击。
变量覆盖漏洞大多由函数使用不当导致,经常引发变量覆盖的漏洞有:extract()函数和parse_str()
函数,import_request_variables()函数则是用在没有开启全局变量注册的时候,调用了这个函数则相当于开启了全局变量注册。另外部分应用利用$$的方式注册变量没验证已有变量导致覆盖。
register_globals
的意思是注册为全局变量,如果为on的时候,传递过来的值会被直接注册为全局变量直接使用
全局变量覆盖
代码示例1:
1 |
|
当register_globals=Off的时候,下一个程序接收的时候应该用$_GET[‘id’]来接受传递过来的值;
当register_globals=On的时候,下一个程序可以直接使用$id来接受值,也可以用$_GET[‘id’]来接受传递过来的值。
tips:如果上面的代码中,已经对变量$id赋了初始值,比如$id=0,那么即使在URL中有/test.php?id=1,也不会将变量覆盖,id值为0
代码示例2:
1 |
|
因为变量a未初始化,提交?a=123&b=456只回显456
当提交?GLOBALS[a]=123&b=456时 都有回显
GLOBALS[a]用于覆盖
PHP » 4.2.0 版开始配置文件中 PHP 指令 register_globals 的默认值从 on 改为 off 了,自 PHP 5.3.0 起废弃并将自 PHP 5.4.0 起移除。
extract()变量覆盖
代码示例:
1 |
|
http://127.0.0.1/CTF/blfg.php?auth=1 即可绕过服务器端逻辑
parse_str()变量覆盖
parse_str() 函数把查询字符串解析到变量中,如果没有array 参数,则由该函数设置的变量将覆盖已存在的同名变量。
1 |
|
tips:
parse_str()类似的函数还有mb_parse_str(),用法基本一致。
import_request_variables变量覆盖
覆盖原理其实基础知识里面也写了
import_request_variables 函数可以在 register_global = off 时,把 GET/POST/Cookie 变量导入全局作用域中。
1 |
|
遍历初始化变量
使用foreach来遍历数组中的值,然后再将获取到的数组键名作为变量,数组中的键值作为变量的值。因此就产生了变量覆盖漏洞。
代码示例:
1 |
|
0x03 漏洞防御
- 确保register_globals=OFF
- 如果不能自定义php.ini,那么应该在代码中严格控制
- 熟悉造成变量覆盖的函数和方法,检查用户是否能控制变量的来源
- 养成初始化变量的好习惯
0x04 漏洞挖掘
由于变量覆盖漏洞通常要结合应用其他功能代码来实现完整攻击,所以挖掘一个可用的变量覆盖漏洞不仅仅要考虑的是能够实现变量覆盖,还要考虑后面的代码能不能让这个漏洞利用起来。
由函数导致的变量覆盖比较好挖掘,只要搜寻参数带有变量的extract()、parse_str()函数,然后去回溯变量是否可控。关于我们说过的使用双$符号注册变量会导致变量覆盖,我们可以通过搜“$$”这个关键字去挖掘。
0x05 总结
这个漏洞单独出现利用点很难(尤其是在黑盒情况),要看这个漏洞利用价值如何,还要看后面的代码能否被利用
白盒情况下,说不定运气好还可以挖出一些漏洞
0x06 参考资料
https://www.cnblogs.com/xiaozi/p/7768580.html
https://www.jianshu.com/p/a4d782e91852
https://blog.csdn.net/qq_36197704/article/details/81623825
<<白帽子讲Web安全>>