PHP 代码审计学习计划是从 BuleCms->SeaCms->DedeCms->PhpCms 逐一进行审计,这里审计的是 SeaCms v6.45
SeaCms 是多文件入口的 Cms,思路还是先通读 index.php
和 admin/index.php
和 admin/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.php
和 admin/index.php
和 admin/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
变量传入要执行的代码