SeaCms 代码审计

PHP 代码审计学习计划是从 BuleCms->SeaCms->DedeCms->PhpCms 逐一进行审计,这里审计的是 SeaCms v6.45

SeaCms 是多文件入口的 Cms,思路还是先通读 index.phpadmin/index.phpadmin/login.php 文件,借此了解 Cms 对参数的全局过滤和连接数据库的编码和其它的一些安全措施

SeaCms 用 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;
}

且数据库编码并没有设置为 GBK,这种情况下可能产生的 SQL 注入我知道的有两种

  • 把客户端IP存储进数据库,且客户端IP可以伪造
  • SQL 语句参数没有引号包裹或者用 反引号 等包裹

在我通读完 index.phpadmin/index.phpadmin/login.php 文件后并没有找到漏洞,前台功能较少,后台我注意到有一个模板编辑功能,审计上一套 BuleCms 的时候,就是前台 SQL 注入配合由后台模板编辑产生的文件写入进行一个组合拳 getshell

SeaCms 也存在由后台模板编辑产生的文件写入漏洞,但是这个写入有文件后缀限制,只能是 html/htm/js/css/txt

$dirTemplate="../templets";
elseif($action=='saveCus')
{
	if($filedir == '')
	{
		ShowMsg('未指定要编辑的文件或文件名不合法', '-1');
		exit();
	}
	if(substr(strtolower($filedir),0,11)!=$dirTemplate){
		ShowMsg("只允许编辑templets目录!","admin_template.php");
		exit;
	}
	$filetype=getfileextend($filedir);
	if ($filetype!="html" && $filetype!="htm" && $filetype!="js" && $filetype!="css" && $filetype!="txt")
	{
		ShowMsg("操作被禁止!","admin_template.php");
		exit;
	}
	$folder=substr($filedir,0,strrpos($filedir,'/'));
	if(!is_dir($folder)){
		ShowMsg("目录不存在!","admin_template.php");
		exit;
	}
	$content = stripslashes($content);
	$content = m_eregi_replace("##textarea","<textarea",$content);
	$content = m_eregi_replace("##/textarea","</textarea",$content);
	$content = m_eregi_replace("##form","<form",$content);
	$content = m_eregi_replace("##/form","</form",$content);
	createTextFile($content,$filedir);
	ShowMsg("操作成功!","admin_template.php?action=custom");
	exit;
}

写入目录限制在 ../templets 上,可以通过目录穿越绕过这一点,这时候是写入文件内容可控,文件名后缀只能是 html/htm/js/css/txt ,我在通读代码的时候注意到 admin/login.php 有一个文件包含操作

include('templets/login.htm');

很好,这时候就可以通过写入一句话到 login.htm 文件中

再访问 admin/login.php 即可 getshell

后台的 getshell,这时候审审有没有逻辑漏洞/sql注入/未授权漏洞(XSS暂时不考虑)拿到后台权限,就可以打一套组合拳,登录处的处理逻辑没找到漏洞点,编辑模板也不存在未授权,只能找一找 sql 注入了

在我审计这套 Cms 的时候没有特别注意去寻找哪些 sql 语句的参数是没有被包裹或者被反引号包裹的,所以一直没有头绪,没有头绪就换其它思路,有未授权的上传接口,但是没有 __wakeup 函数无法 phar 反序列化,文件包含没有找到可控的点,这里陷入了僵局

还是太菜了,查阅网上有关 SeaCms 的审计文章,前台有个 sql 注入和 rce,sql注入产生在 comment/api/index.php 文件

$sql = "SELECT id,uid,username,dtime,reply,msg,agree,anti,pic,vote,ischeck FROM sea_comment WHERE m_type=$type AND id in ($ids) ORDER BY id DESC";

$ids 可控,无引号包裹,这条语句是在 Readrlist 函数执行的,也正是因为在另一个函数里面,当时审计的有点疲惫了,没有跟进去,$ids 的传递也是很简单的

还有一个反引号包裹参数的后台 sql 注入

查阅文章提及到一个前台 rce,漏洞原因是 eval 执行的内容部分可控,在 include/main.class.php 文件,文件代码量很大,功能是用来解析模板标签的,漏洞核心代码如下

function parseIf($content){
    $labelRule = buildregx("{if:(.*?)}(.*?){end if}","is");
    preg_match_all($labelRule,$content,$iar);
    $strIf=$iar[1][$m];
    @eval("if(".$strIf."){\$ifFlag=true;}else{\$ifFlag=false;}");
}

在 phpstorm 中跟踪哪里调用了 parseIf 函数,search.php 文件调用这个函数

function echoSearchPage(){
    $content = str_replace("{searchpage:ordername}",$order,$content);
	$content=$mainClassObj->parseIf($content);
}

$content 值是 cascade.html/search.html 其中一个文件的内容,templets/default/html/cascade.html 文件存在 {searchpage:ordername} 标签,图片中的 payload 对应的 $content 变量值是 templets/default/html/cascade.html 文件里的内容,$order 通过传参传入

$order 变量传入要执行的代码