exp
xxx/search.php?searchtype=5&tid=&area=eval($_POST[1])
分析
先去search.php看一下这几个参数的位置(13-31行)
$page = (isset($page) && is_numeric($page)) ? $page : 1;
$searchtype = (isset($searchtype) && is_numeric($searchtype)) ? $searchtype : -1;
$tid = (isset($tid) && is_numeric($tid)) ? intval($tid) : 0;
if(!isset($searchword)) $searchword = '';
$action = $_REQUEST['action'];
$searchword = RemoveXSS(stripslashes($searchword));
$searchword = addslashes(cn_substr($searchword,20));
if($cfg_notallowstr !='' && m_eregi($cfg_notallowstr,$searchword))
{
ShowMsg("你的搜索关键字中存在非法内容,被系统禁止!","index.php","0",$cfg_search_time*1000);
exit();
}
if($searchword==''&&$searchtype!=5)
{
ShowMsg('关键字不能为空!','index.php','0',$cfg_search_time*1000);
exit();
}
echoSearchPage();
令searchtype=5,满足25行的条件if($searchword==''&&$searchtype!=5)
第184行
$content=$mainClassObj->parseIf($content);
调用了函数parseIf()
,定位函数看一下功能。位于/include/main.class.php第3087行
function parseIf($content){
if (strpos($content,'{if:')=== false){
return $content;
}else{
$labelRule = buildregx("{if:(.*?)}(.*?){end if}","is");
$labelRule2="{elseif";
$labelRule3="{else}";
preg_match_all($labelRule,$content,$iar);
$arlen=count($iar[0]);
$elseIfFlag=false;
for($m=0;$m<$arlen;$m++){
$strIf=$iar[1][$m];
$strIf=$this->parseStrIf($strIf);
$strThen=$iar[2][$m];
$strThen=$this->parseSubIf($strThen);
if (strpos($strThen,$labelRule2)===false){
if (strpos($strThen,$labelRule3)>=0){
$elsearray=explode($labelRule3,$strThen);
$strThen1=$elsearray[0];
$strElse1=$elsearray[1];
@eval("if(".$strIf."){\$ifFlag=true;}else{\$ifFlag=false;}");
if ($ifFlag){ $content=str_replace($iar[0][$m],$strThen1,$content);} else {$content=str_replace($iar[0][$m],$strElse1,$content);}
}else{
@eval("if(".$strIf.") { \$ifFlag=true;} else{ \$ifFlag=false;}");
if ($ifFlag) $content=str_replace($iar[0][$m],$strThen,$content); else $content=str_replace($iar[0][$m],"",$content);}
}else{
$elseIfArray=explode($labelRule2,$strThen);
$elseIfArrayLen=count($elseIfArray);
$elseIfSubArray=explode($labelRule3,$elseIfArray[$elseIfArrayLen-1]);
$resultStr=$elseIfSubArray[1];
$elseIfArraystr0=addslashes($elseIfArray[0]);
@eval("if($strIf){\$resultStr=\"$elseIfArraystr0\";}");
for($elseIfLen=1;$elseIfLen<$elseIfArrayLen;$elseIfLen++){
$strElseIf=getSubStrByFromAndEnd($elseIfArray[$elseIfLen],":","}","");
$strElseIf=$this->parseStrIf($strElseIf);
$strElseIfThen=addslashes(getSubStrByFromAndEnd($elseIfArray[$elseIfLen],"}","","start"));
@eval("if(".$strElseIf."){\$resultStr=\"$strElseIfThen\";}");
@eval("if(".$strElseIf."){\$elseIfFlag=true;}else{\$elseIfFlag=false;}");
if ($elseIfFlag) {break;}
}
$strElseIf0=getSubStrByFromAndEnd($elseIfSubArray[0],":","}","");
$strElseIfThen0=addslashes(getSubStrByFromAndEnd($elseIfSubArray[0],"}","","start"));
if(strpos($strElseIf0,'==')===false&&strpos($strElseIf0,'=')>0)$strElseIf0=str_replace('=', '==', $strElseIf0);
@eval("if(".$strElseIf0."){\$resultStr=\"$strElseIfThen0\";\$elseIfFlag=true;}");
$content=str_replace($iar[0][$m],$resultStr,$content);
}
}
return $content;
}
}
可以看到函数中有多出@eval,并且包含有变量,下面我们就对变量进行分析。
第3107行:@eval("if(".$strIf."){\$ifFlag=true;}else{\$ifFlag=false;}");
我们看一下这个变量$strIf是怎么来的
第3098和mai声明了变量$strIf
$strIf=$iar[1][$m];
$strIf=$this->parseStrIf($strIf);
strif作为&iar[1]的元素,那么我们来看一下这个&iar是哪来的,在第3094行
preg_match_all($labelRule,$content,$iar);
$labelRule = buildregx("{if:(.*?)}(.*?){end if}","is");
这里有一个正则匹配,$iar是匹配的结果。buildregx是对正则表达式格式加工的函数。
看一下被匹配的$content的内容。$content是在search.php中调用函数作为参数过来的,去search.php找一找。
if($cfg_iscache){
if(chkFileCache($cacheName)){
$content = getFileCache($cacheName);
}else{
$content = parseSearchPart($searchTemplatePath);
setFileCache($cacheName,$content);
}
}else{
$content = parseSearchPart($searchTemplatePath);
}
(117-126行)
在/install/config.cache.ini.php第80行可以知道,$cfg_iscache = ‘1’;,默认为1.上面定义了$searchTemplatePath=/templets/default/html/cascade.html
chkFileCache函数在common.func.php2395行,是用来判断是否存在相同的文件。如果有就直接从文件获取,没有就执行$content = parseSearchPart($searchTemplatePath);
,下面190行是parseSearchPart函数。
function parseSearchPart($templatePath)
{
global $mainClassObj,$tid;
$currentTypeId = empty($tid)?0:$tid;
$content=loadFile(sea_ROOT.$templatePath);
$content=$mainClassObj->parseTopAndFoot($content);
$content=$mainClassObj->parseAreaList($content);
$content=$mainClassObj->parseHistory($content);
$content=$mainClassObj->parseSelf($content);
$content=$mainClassObj->parseGlobal($content);
$content=$mainClassObj->parseMenuList($content,"",$currentTypeId);
$content=$mainClassObj->parseVideoList($content,$currentTypeId);
$content=$mainClassObj->parsenewsList($content,$currentTypeId);
$content=$mainClassObj->parseTopicList($content);
return $content;
}
这几个函数的功能都差不多,cascade.html作为一个模板的作用,各个函数都是为其添加各自的内容的
再往下来看到一个对searchtype的判断。
if(intval($searchtype)==5)
{
$tname = !empty($tid)?getTypeNameOnCache($tid):'全部';
$jq = !empty($jq)?$jq:'全部';
$area = !empty($area)?$area:'全部';
$year = !empty($year)?$year:'全部';
$yuyan = !empty($yuyan)?$yuyan:'全部';
$letter = !empty($letter)?$letter:'全部';
$state = !empty($state)?$state:'全部';
$ver = !empty($ver)?$ver:'全部';
$money = !empty($money)?$money:'全部';
$content = str_replace("{searchpage:type}",$tid,$content);
$content = str_replace("{searchpage:typename}",$tname ,$content);
$content = str_replace("{searchpage:year}",$year,$content);
$content = str_replace("{searchpage:area}",$area,$content);
$content = str_replace("{searchpage:letter}",$letter,$content);
$content = str_replace("{searchpage:lang}",$yuyan,$content);
$content = str_replace("{searchpage:jq}",$jq,$content);
if($state=='w'){$state2="完结";}elseif($state=='l'){$state2="连载中";}else{$state2="全部";}
if($money=='m'){$money2="免费";}elseif($money=='s'){$money2="收费";}else{$money2="全部";}
$content = str_replace("{searchpage:state}",$state2,$content);
$content = str_replace("{searchpage:money}",$money2,$content);
$content = str_replace("{searchpage:ver}",$ver,$content);
$content=$mainClassObj->parsePageList($content,"",$page,$pCount,$TotalResult,"cascade");
$content=$mainClassObj->parseSearchItemList($content,"type");
$content=$mainClassObj->parseSearchItemList($content,"year");
$content=$mainClassObj->parseSearchItemList($content,"area");
$content=$mainClassObj->parseSearchItemList($content,"letter");
$content=$mainClassObj->parseSearchItemList($content,"lang");
$content=$mainClassObj->parseSearchItemList($content,"jq");
$content=$mainClassObj->parseSearchItemList($content,"state");
$content=$mainClassObj->parseSearchItemList($content,"ver");
$content=$mainClassObj->parseSearchItemList($content,"money");
}else
对变量进行了是否为空的判断,传入了参数就使用用户传入值否则为默认值。各变量被替换到模板里面。
这时候$content就是原来cascade.html经过替换组装后的内容。
这时候content进入parseIf()函数,经过preg_match_all($labelRule,$content,$iar);
的匹配后会匹配出{if:(.*?)}这种形式的内容作为$strIf的值。在cascade.html中可以看到要匹配的内容
<dl>
<dd> {seacms:typeitemlist}{if: [typeitemlist:value]={searchpage:typename}}<b><a href="[typeitemlist:link]">[typeitemlist:value]</a></b>{else}<a href="[typeitemlist:link]">[typeitemlist:value]</a>{end if} {/seacms:typeitemlist}</dd>
<dd> {seacms:areaitemlist}{if: [areaitemlist:value]={searchpage:area}}<b><a href="[areaitemlist:link]">[areaitemlist:value]</a></b>{else}<a href="[areaitemlist:link]">[areaitemlist:value]</a>{end if} {/seacms:areaitemlist}</dd>
<dd> {seacms:yearitemlist}{if: [yearitemlist:value]={searchpage:year}}<b><a href="[yearitemlist:link]">[yearitemlist:value]</a></b>{else}<a href="[yearitemlist:link]">[yearitemlist:value]</a>{end if} {/seacms:yearitemlist}</dd>
<dd> {seacms:letteritemlist}{if: [letteritemlist:value]={searchpage:letter}}<b><a href="[letteritemlist:link]">[letteritemlist:value]</a></b>{else}<a href="[letteritemlist:link]">[letteritemlist:value]</a>{end if} {/seacms:letteritemlist}</dd>
<dd> {seacms:langitemlist}{if: [langitemlist:value]={searchpage:lang}}<b><a href="[langitemlist:link]">[langitemlist:value]</a></b>{else}<a href="[langitemlist:link]">[langitemlist:value]</a>{end if} {/seacms:langitemlist}</dd>
<dd> {seacms:jqitemlist}{if: [jqitemlist:value]={searchpage:jq}}<b><a href="[jqitemlist:link]">[jqitemlist:value]</a></b>{else}<a href="[jqitemlist:link]">[jqitemlist:value]</a>{end if} {/seacms:jqitemlist}</dd>
<dd> {seacms:stateitemlist}{if: [stateitemlist:value]={searchpage:state}}<b><a href="[stateitemlist:link]">[stateitemlist:value]</a></b>{else}<a href="[stateitemlist:link]">[stateitemlist:value]</a>{end if} {/seacms:stateitemlist}</dd>
<dd> {seacms:veritemlist}{if: [veritemlist:value]={searchpage:ver}}<b><a href="[veritemlist:link]">[veritemlist:value]</a></b>{else}<a href="[veritemlist:link]">[veritemlist:value]</a>{end if} {/seacms:veritemlist}</dd>
<dd> {seacms:moneyitemlist}{if: [moneyitemlist:value]={searchpage:money}}<b><a href="[moneyitemlist:link]">[moneyitemlist:value]</a></b>{else}<a href="[moneyitemlist:link]">[moneyitemlist:value]</a>{end if} {/seacms:moneyitemlist}</dd>
</dl>
匹配到的内容是形如xx=xx这种形式,会经过parseStrIf()函数处理,看上面main.class.php的3099行。
function parseStrIf($strIf)
{
if(strpos($strIf,'=')===false)
{
return $strIf;
}
if((strpos($strIf,'==')===false)&&(strpos($strIf,'=')>0))
{
$strIf=str_replace('=', '==', $strIf);
}
$strIfArr = explode('==',$strIf);
return (empty($strIfArr[0])?'NULL':$strIfArr[0])."==".(empty($strIfArr[1])?'NULL':$strIfArr[1]);
}
这个函数的作用就是看一下匹配到的内容有没有等号,没有直接返回,有的话将单等号替换成双等号返回。
然后作为$strIf的值拼接进eval执行。