这是一个比较有意思的东西,但是成功利用起来并不容易,呵呵。
首先看config_rglobals.php文件,摘的一段代码如下。这里作者本意是为了帮我们注册变量的,但是他却疏忽了我们不但能注册变量,还能覆盖一些变量。config_rglobals_magic.php也有同样的问题
…………………………………………………………………………
if(is_array($_GET)){
foreach($_GET AS $key => $value){ $$key = $value; }
}//可以覆盖任意变量
…………
…………………………………………………………………………
说这个是漏洞还太早了,要结合下面的代码看到底有没有好利用的地方,看config_base.php文件可以发现这样一段代码
…………………………………………………………………………
…………
//载入用户配置的系统变量
require_once(DEDEINC."/config_hand.php");
…………
if($phpold==1){ //低版本强制检查变量
$cfg_isMagic = false;
$cfg_registerGlobals = false;
}else{
$cfg_registerGlobals = @ini_get("register_globals");
$cfg_isMagic = @ini_get("magic_quotes_gpc");
}
//检测系统是否注册外部变量
if(!$cfg_isMagic) require_once(DEDEINC."/config_rglobals_magic.php");
else if(!$cfg_registerGlobals || $cfg_needFilter) require_once(DEDEINC."/config_rglobals.php");
…………………………………………………………………………
从这里可以看出,在register_globals=off 我们可以注册自己的变量并覆盖之前的值。而在register_globals=on时由于服务器配置的原因,ini_get()函数在很多时候是会失效的。简单的说,就是即使register_globals=On,也可能是ini_get('register_globals') =FALSE,所以依旧可以导致变量覆盖。但是能覆盖的只能是在这之前的内容,向前找看到config_hand.php文件里面定义的值似乎都能覆盖,但是真的能覆盖吗?再向前看到这样的代码,原来程序还是有考虑的
…………………………………………………………………………
//全局安全检测
foreach($ckvs as $ckv){
foreach($$ckv AS $_k => $_v){
if(eregi("^(globals|cfg_)",$_k)) unset(${$ckv}[$_k]);
}
}
………………………………………………………………………
上面代码的意思是cfg_开头的变量不让从外部提交,发现了就unset掉,这样看的话config_hand.php里面cfg_开头的全局变量都是不让我们覆盖的。看到这里也许有人觉得没戏了。厄,多数情况下是这样的,但是别忘记了我们还有Zend_Hash_Del_Key_Or_Index漏洞,在PHP < 4.4.3, 5 <= PHP < 5.1.4时这个unset并不能释放我们的变量,于是这里就带来了隐患。
下面说个有意思的利用方式,就是选择覆盖$cfg_mediatype来上传任意文件呢?但是这个地方是有限制的,在config_base.php中用require_once函数调用文件config_rglobals.php之前有一段这样的代码
………………………………………………………………
//检测上传的文件中是否有危险代码,有直接退出处理
if( !isset($cfg_NoUploadSafeCheck) ){
if (is_array($_FILES)) {
foreach($_FILES AS $_name => $_value){
${$_name} = $_value['tmp_name'];
$_fp = @fopen(${$_name},'r');
$_fstr = @fread($_fp,filesize(${$_name}));
@fclose($_fp);
if($_fstr!='' && ereg("<(\?|%)",$_fstr)){
echo "你上传的文件中含有危险内容,程序终止处理!";
exit();
}
}
}}
…………………………………………………………………
只有$cfg_NoUploadSafeCheck非空才可以绕过这段检查但是由于在这段代码后才用函数require_once来调用文件config_rglobals.php注册变量,所以只有在php设置register_globals=on时我们才可以提交$cfg_NoUploadSafeCheck绕过过滤上传php脚本
下面我们来看如何具体利用,看文件
…………………………………………………………
\include\dialoguser\medias_upload.php
…………
if(!CheckAddonType($uploadfile_name)){
ShowMsg("你所上传的文件类型被禁止,系统只允许上传<br>".$cfg_mb_mediatype." 类型附件!","-1");
exit();
}
$fs = explode(".",$uploadfile_name);
$sname = trim($fs[count($fs)-1]);
if($sname==''){
ShowMsg("你所上传的文件无法识别,系统禁止上传<br />","-1");
exit();
}
$nowtme = mytime();
$filename_name = dd2char($cfg_ml->M_ID."0".strftime("%y%m%d%H%M%S",$nowtme)."0".mt_rand(1000,9999));
$filename = $filename_name.".".$sname; //这里用不带目录的文件名作标题
$fileurl = $rootdir."/".$filename;
$fullfilename = $cfg_basedir.$fileurl;
//严格检查最终的文件名
if(!CheckAddonType($fullfilename) || eregi("\.(php|asp|pl|shtml|jsp|cgi|aspx)",$fullfilename)){
ShowMsg("你所上传的文件类型被禁止,系统只允许上传<br>".$cfg_mb_mediatype." 类型附件!","-1");
exit();
}
@move_uploaded_file($uploadfile,$fullfilename);
……
……………………………………………………………………….
对于检查最终的文件名部分的代码,asa并不在黑名单里面。剩下的就是CheckAddonType函数的过滤了,我们找到相关代码
……………………………………………………………………
\\include\inc_memberlogin.php
//检测用户的附件类型
function CheckAddonType($aname){
global $cfg_mb_mediatype;
if(empty($cfg_mb_mediatype)){
$cfg_mb_mediatype = "jpg|gif|png|bmp|swf|mpg|mp3|rm|rmvb|wmv|asf|wma|zip|rar|doc|xsl|ppt|wps";
}
$anames = explode('.',$aname);
$atype = $anames[count($anames)-1];
if(count($anames)==1) return false;
else{
$atype = strtolower($atype);
$cfg_mb_mediatypes = explode('|',trim($cfg_mb_mediatype));
if(in_array($atype,$cfg_mb_mediatypes)) return true;
else return false;
}
}
……………………………………………………………………………..
依然是依据$cfg_mb_mediatype来过滤的,综合上面的分析,可以将之覆盖为asa来达到我们的目的。实战中要利用起来真不容易,需要ini_get失效,register_globals 为on,php本身Zend_Hash_Del_Key_Or_Index的洞没有被修补,还有更不幸的是需要支持asa。
Dedecms V5
暂无
暂无评论