看文章的时候看到变量覆盖,就去学习了一波。
全局变量覆盖
http://php.net/manual/zh/security.globals.php
php超级全局变量
1 2 3 4 5 6 7 8 9 | $GLOBALS, 所有全局变量数组 $_SERVER, 服务器环境变量数组 $_GET,通过GET方法传递给脚本的变量数组 $_POST, 通过POST方法传递给脚本的变量数组 $_COOKIE,cookie变量数组 $_REQUEST,所有用户输入的变量数组,包括$_GET, $_POST和$_COOKIE所包含的输入内容 $_FILES,与文件上传相关得变量数组 $_ENV,环境变量数组 $_SESSION,会话变量数组 |
当register_global=ON时,变量来源可能是各个不同的地方,比如页面的表单,Cookie等 提交请求URL:http://www.a.com/test.php?auth=1,变量$auth将自动得到赋值
|
|
防范办法
register_globals=off 变量初始化
extract()变量覆盖
int extract ( array &$array [, int $flags = EXTR_OVERWRITE [, string $prefix = NULL ]] ) 本函数用来将变量从数组中导入到当前的符号表中
|
|
http://www.a.com/test.php?auth=1 就会注册一个$auth,其值为1,因为默认为EXTR_OVERWRITE,所以就算初始化了也能覆盖
防范方法
在调用extrace时使用EXTR_SKIP,确保已有变量不会被覆盖
遍历初始化变量
|
|
首先$_GET是一个数组
1
| Array ( [chs] => 1 ) |
然后$key=chs
那么$$key=$chs
,所以可覆盖$chs
的值
防范方法
少写$$k
这样的代码(误
parse_str()变量覆盖
如果 encoded_string 是 URL 传递入的查询字符串(query string),则将它解析为变量并设置到当前作用域(如果提供了 result 则会设置到该数组里 )
|
|
test.php?var=1
输出就会变成1
单独输出$_SERVER['QUERY_STRING']
为var=1
所以$var=0
就被覆盖了
与parse_str()类似的函数还有mb_parse_str()
防范方法
不会Orz…
import_request_variavles变量覆盖
bool import_request_variables ( string $types [, string $prefix ] )
将 GET/POST/Cookie 变量导入到全局作用域中。如果你禁止了 register_globals,但又想用到一些全局变量,那么此函数就很有用。
|
|
这里设置的是G,所以GET请求中的变量将会导入到全局中,所以http://www.a.com/test1.php?auth=1
,将会导致$auth
被覆盖
实例
|
|
$where
变量没有初始化,所以可以用sql语句来覆盖掉$where
变量
u.php?action=list&where={sql}
|
|
这里就涉及到了遍历变量覆盖,提交jfrom[groups][]=7
,$this->data->groups[]
就会被改为7,成功注册了个管理员账号
然后我根据自己的理解写了个覆盖原理代码
|
|
结果为
1 2 3 4 5 6 7 8 9 10 11 | /var/www/html/test.php:3: array (size=1) 'groups' => array (size=1) 0 => int 1 /var/www/html/test.php:9: array (size=1) 'groups' => array (size=1) 0 => string '7' (length=1) |
虽然是string类型,感觉php弱类型会把它改为int吧(误
部分代码为
|
|
经过上面内容的学习,看到foreach就懂了。
正常流程
1. $_REQUEST
接受正常请求,将数组名与值分离
2. 判断数组名是否为空,以及数组名是否有黑名单中的字符,若两者都成立,退出并显示警告
3. 上述过程全都没毛病,将各种请求遍历注册为变量
4. 遍历,将请求中的数组名注册为变量并赋值
如果我们的请求为/test.php?_POST[GLOBALS]
[cfg_dbhost]=MYSQL外链IP&_POST[GLOBALS] [cfg_dbuser]=MYSQL的账号&_POST[GLOBALS][cfg_dbpwd]=MYSQL的密码& _POST[GLOBALS]
[cfg_dbname]=自己的dedecms的数据库
首先第2步所判断的数组名就为_POST
,绕过了黑名单判断,并且注册了$_POST
然后第4步时注册了$GLOBALS
,并将赋值成数组
然后就更改数据库为我们的数据库
EOF
参考资料: http://www.cnseay.com/1839/ http://blog.csdn.net/hitwangpeng/article/details/45972099