看文章的时候看到变量覆盖,就去学习了一波。
全局变量覆盖
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