用户
搜索

[参加活动] Metinfo 6.1.2 SQL注入 heatlevel

  • TA的每日心情
    无聊
    4 天前
  • 签到天数: 164 天

    连续签到: 1 天

    [LV.7]常住居民III

    i春秋作家

    Ashe

    Rank: 7Rank: 7Rank: 7

    15

    主题

    169

    帖子

    1940

    魔法币
    收听
    0
    粉丝
    2
    注册时间
    2016-11-9

    i春秋签约作者春秋游侠春秋文阁

    发表于 2018-10-11 10:56:16 23918650

    0x01 前言

    这个本来是不想放出来的,因为metinfo这套cms毕竟使用人数还是挺多的,影响范围也很广。在前两个版本我就提交过此漏洞了鉴于一直不修复。所幸放出来给大家共同学习一下。看到这还请提醒厂商尽快修复了。不过我会在最后留下解决方案。

    注:只供学习参考,任何用来违法犯罪的与本人无关,违法犯罪快走开,违法犯罪快走开,违法犯罪快走开。

    0x02 漏洞分析

    漏洞文件:/var/www/html/metinfo6.1.2/app/system/message/web/message.class.php
    漏洞函数:add          37-51行

        public function add($info) {
                global $_M;
                if(!$_M[form][id]){
           $message=DB::get_one("select * from {$_M[table][column]} where module= 7 and lang ='{$_M[form][lang]}'");
           $_M[form][id]=$message[id];
                }
                $met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and  name= 'met_fd_ok' and columnid = {$_M[form][id]}");
        $_M[config][met_fd_ok]= $met_fd_ok[value];
                if(!$_M[config][met_fd_ok])okinfo('javascript:history.back();',"{$_M[word][Feedback5]}");
                if($_M[config][met_memberlogin_code]){
                        if(!load::sys_class('pin', 'new')->check_pin($_M['form']['code'])){
    
                                                 okinfo(-1, $_M['word']['membercode']);
                        }
            }

    漏洞触发点:
    $met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and  name= 'met_fd_ok' and columnid = {$_M[form][id]}");

    由于无单引号过滤导致sql注入,这个时候尝试注入发现关键词全被替换了,无法注入。于是查看__controler函数发现调用了父类的初始化函数。

    class feedback extends web

    跟进web类,没有对用户传入的数据进行过滤等操作,却初始化了common类

    class web extends common

    查看Common类的初始化函数发现了问题所在

        public function __construct() {
                global $_M;//全局数组$_M
                ob_start();//开启缓存
                $this->load_mysql();//数据库连接
                $this->load_form();//表单过滤
                $this->load_lang();//加载语言配置
                $this->load_config_global();//加载全站配置数据
                $this->load_url_site();
                $this->load_config_lang();//加载当前语言配置数据
                $this->load_url();//加载url数据
        }

    跟踪 $this→load_form() 函数

        protected function load_form() {
                global $_M;
                $_M['form'] =array();
                isset($_REQUEST['GLOBALS']) && exit('Access Error');
                foreach($_COOKIE as $_key => $_value) {
                        $_key{0} != '_' && $_M['form'][$_key] = daddslashes($_value);
                }
                foreach($_POST as $_key => $_value) {
                        $_key{0} != '_' && $_M['form'][$_key] = daddslashes($_value);
                }
                foreach($_GET as $_key => $_value) {
                        $_key{0} != '_' && $_M['form'][$_key] = daddslashes($_value);
                }
                if(is_numeric($_M['form']['lang'])){//伪静态兼容
                        $_M['form']['page'] = $_M['form']['lang'];
                        $_M['form']['lang'] = '';
                }
                if($_M['form']['metid'] == 'list'){
                        $_M['form']['list'] = 1;
                        $_M['form']['metid'] = $_M['form']['page'];
                        $_M['form']['page'] = 1;
                }
                if(!preg_match('/^[0-9A-Za-z]+$/', $_M['form']['lang']) && $_M['form']['lang']){
                        echo "No data in the database,please reinstall.";
                        die();
                }
        }

    把COOKIE、POST、GET 传入 daddslashes函数进行过滤

    function daddslashes($string, $force = 0) {
            !defined('MAGIC_QUOTES_GPC') && define('MAGIC_QUOTES_GPC',         get_magic_quotes_gpc());
            if(!MAGIC_QUOTES_GPC || $force) {
                    if(is_array($string)) {
                            foreach($string as $key => $val) {
                                    $string[$key] = daddslashes($val, $force);
                            }
                    } else {
                            if(!defined('IN_ADMIN')){
                                    $string = trim(addslashes(sqlinsert($string)));
                            }else{
                                    $string = trim(addslashes($string));
                            }
                    }
            }
            return $string;
    }

    这里判断是否开启了get_magic_quotes_gpc() 如果没开启或者 $force !=0 就进入过滤。
    然而最重要的环节在这里

                            if(!defined('IN_ADMIN')){
                                    $string = trim(addslashes(sqlinsert($string)));
                            }else{
                                    $string = trim(addslashes($string));
                            }

    判断  IN_ADMIN 常量是否已经定义了,如果没定义就使用$string = trim(addslashes(sqlinsert($string)));来过滤我们的值

    而如果定义了就使用$string = trim(addslashes($string));来过滤。

    刚刚我们进行sql注入测试失败而且语句被过滤了, addslashes只过滤特殊字符,所以我们肯定是被 sqlinsert函数给过滤了。导致我们无法sql注入。至于sqlinsert函数我就不贴出来了,我们要做的是饶过这个函数,而不是饶过他这个规则。

    defined('IN_ADMIN') 我们需要找这个常量在哪里定义的。其实写这句话有点多余,看过我之前几篇Metinfo漏洞的话应该就会发现问题了。我写过一个关于/admin/index.php文件任意调用带do方法的问题。

    然后我们打开这个文件看一下。

    <?php
    define('IN_ADMIN', true);
    $M_MODULE='admin';
    if(@$_GET['m'])$M_MODULE=$_GET['m'];
    if(@!$_GET['n'])$_GET['n']="index";
    if(@!$_GET['c'])$_GET['c']="index";
    if(@!$_GET['a'])$_GET['a']="doindex";
    @define('M_NAME', $_GET['n']);
    @define('M_MODULE', $M_MODULE);
    @define('M_CLASS', $_GET['c']);
    @define('M_ACTION', $_GET['a']);
    require_once '../app/system/entrance.php';
    ?>

    没错这个常量就是在这个文件定义的。而且他可以调用任意带do方法。不过问题又来了,漏洞函数是add并且不带do,那就找调用白,于是找到 domessage这个函数。

    domessage方法                18-24

      public function domessage() {
                    global $_M;
                    if($_M['form']['action'] == 'add'){
                            $this->check_field();
                            $this→add($_M['form']);

    这里在调用 add方法之前先调用了 check_field方法,我们要做的就是保证程序能够顺利执行到add方法,研究了一会发现只需要正常留言,把它传递的参数拷下来就ok了。
    然后顺利执行到了add方法,成功的进行了sql注入。

    payload:http://127.0.0.1/metinfo6//admin/index.php?m=web&n=message&c=message&a=domessage&action=add&lang=cn¶137=1¶186=1¶138=1¶139=1¶140=1&id=42

    这里说一下这个id=42,这个值42是不能修改的,目的是让他返回验证码错误,饶过了第一层判断。

                    if(!$_M[config][met_fd_ok])okinfo('javascript:history.back();',"{$_M[word][Feedback5]}");
                    if($_M[config][met_memberlogin_code]){
                            if(!load::sys_class('pin', 'new')->check_pin($_M['form']['code'])){
    
                                                     okinfo(-1, $_M['word']['membercode']);
                            }
                }

    至于为什么让他饶过第一层判断返回验证码错误,这样的话我们可以布尔盲注,否则只能进行时间注入。这里不多解释,自己研究一下。

    0x03 解决方法

        修改文件:metinfo6.1.2/app/system/message/web/message.class.php
        修改内容:
                $met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and  name= 'met_fd_ok' and columnid = {$_M[form][id]}");
        修改为:
                $met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and  name= 'met_fd_ok' and columnid = ‘{$_M[form][id]}’");
        这样就解决了。

    0x04 漏洞验证脚本

        这里我做了一个脚本来看一下效果


    想要的在后面下载。

    0x05 结束语

        脚本在这。


    游客,如果您要查看本帖隐藏内容请回复


    本帖被以下淘专辑推荐:

    用代码将梦想照进现实!
       修改文件:metinfo6.1.2/app/system/message/web/message.class.php
        修改内容:
                $met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and  name= 'met_fd_ok' and columnid = {$_M[form][id]}");
        修改为:
                $met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and  name= 'met_fd_ok' and columnid = ‘{$_M[form][id]}’");
        这样就解决了。
    使用道具 举报 回复
    修改文件:metinfo6.1.2/app/system/message/web/message.class.php
        修改内容:
                $met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and  name= 'met_fd_ok' and columnid = {$_M[form][id]}");
        修改为:
                $met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and  name= 'met_fd_ok' and columnid = ‘{$_M[form][id]}’");
        这样就解决了。
    使用道具 举报 回复
    修改文件:metinfo6.1.2/app/system/message/web/message.class.php
        修改内容:
                $met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and  name= 'met_fd_ok' and columnid = {$_M[form][id]}");
        修改为:
                $met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and  name= 'met_fd_ok' and columnid = ‘{$_M[form][id]}’");
        这样就解决了。
    使用道具 举报 回复
    <?php
    define('IN_ADMIN', true);
    $M_MODULE='admin';
    if(@$_GET['m'])$M_MODULE=$_GET['m'];
    if(@!$_GET['n'])$_GET['n']="index";
    if(@!$_GET['c'])$_GET['c']="index";
    if(@!$_GET['a'])$_GET['a']="doindex";
    @define('M_NAME', $_GET['n']);
    @define('M_MODULE', $M_MODULE);
    @define('M_CLASS', $_GET['c']);
    @define('M_ACTION', $_GET['a']);
    require_once '../app/system/entrance.php';
    ?>
    使用道具 举报 回复

    修改文件:metinfo6.1.2/app/system/message/web/message.class.php
        修改内容:
                $met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and  name= 'met_fd_ok' and columnid = {$_M[form][id]}");
        修改为:
    使用道具 举报 回复


    修改文件:metinfo6.1.2/app/system/message/web/message.class.php
        修改内容:
                $met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and  name= 'met_fd_ok' and columnid = {$_M[form][id]}");
        修改为:
    使用道具 举报 回复

    修改文件:metinfo6.1.2/app/system/message/web/message.class.php
        修改内容:
                $met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and  name= 'met_fd_ok' and columnid = {$_M[form][id]}");
        修改为:
    使用道具 举报 回复
    发表于 2018-10-20 10:44:58
    修改文件:metinfo6.1.2/app/system/message/web/message.class.php
        修改内容:
                $met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and  name= 'met_fd_ok' and columnid = {$_M[form][id]}");
        修改为:
    使用道具 举报 回复
    发表于 2018-10-11 11:50:38
    大佬厉害了,但为啥只给了个中危呢?有权限限制吗
    使用道具 举报 回复
    发表于 2018-10-11 12:15:16
    修改文件:metinfo6.1.2/app/system/message/web/message.class.php
        修改内容:
                $met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and  name= 'met_fd_ok' and columnid = {$_M[form][id]}");
        修改为:
    使用道具 举报 回复
    发表于 2018-10-11 12:49:36
    厉害啊 大佬
    使用道具 举报 回复
    发表于 2018-10-11 13:25:20
    支持一下~
    使用道具 举报 回复
    发表于 2018-10-11 13:35:20
    学习一下   
    使用道具 举报 回复
    发表于 2018-10-11 14:22:53
    学习学习学习
    使用道具 举报 回复
    发表于 2018-10-11 15:03:36
    学习。。。。
    http://www.anonymou5.com
    使用道具 举报 回复
    发表于 2018-10-11 15:32:58
    学了大佬。
    使用道具 举报 回复
    发表于 2018-10-11 16:58:18
    学习一下!
    The quieter you become,the more you are able to hear......
    使用道具 举报 回复
    发表于 2018-10-11 17:25:52
    学习新姿势,谢谢大佬分享,666666666
    使用道具 举报 回复
    发表于 2018-10-11 17:26:29
    66666666666666
    使用道具 举报 回复
    发表于 2018-10-11 17:35:48
    非常好的文章, 很完整。 思路也清楚
    使用道具 举报 回复
    这个牛逼,谢谢分享
    使用道具 举报 回复
    发表于 2018-10-11 20:08:06
    不错,学习一下
    使用道具 举报 回复
    您需要登录后才可以回帖 登录 | 立即注册