## # 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 # Huge thanks to @zeroSteiner for helping me. Also thanks to @kaospunk. Finally thanks to # Joomscan and various MSF modules for code examples. def initialize super( 'Name' => 'Joomla Version Scanner', 'Description' => %q{ This module scans a Joomla install for information about the underlying operating system and Joomla version. }, 'Author' => [ 'newpid0' ], 'License' => MSF_LICENSE ) register_options( [ OptString.new('TARGETURI', [ true, "The path to the Joomla install", '/']) ], self.class) end def os_fingerprint(response) if not response.headers.has_key?('Server') return "Unkown OS (No Server Header)" end case response.headers['Server'] when /Win32/, /\(Windows/, /IIS/ os = "Windows" when /Apache\// os = "*Nix" else os = "Unknown Server Header Reporting: "+response.headers['Server'] end return os end def fingerprint(response) case response.body when /(.+)<\/version\/?>/i v = $1 out = (v =~ /^6/) ? "Joomla #{v}" : " #{v}" when /system\.css 20196 2011\-01\-09 02\:40\:25Z ian/, /MooTools\.More\=\{version\:\"1\.3\.0\.1\"/, /en-GB\.ini 20196 2011\-01\-09 02\:40\:25Z ian/, /en-GB\.ini 20990 2011\-03\-18 16\:42\:30Z infograf768/, /20196 2011\-01\-09 02\:40\:25Z ian/ out = "1.6" when /system\.css 21322 2011\-05\-11 01\:10\:29Z dextercowley /, /MooTools\.More\=\{version\:\"1\.3\.2\.1\"/, /22183 2011\-09\-30 09\:04\:32Z infograf768/, /21660 2011\-06\-23 13\:25\:32Z infograf768/ out = "1.7" when /Joomla! 1.5/, /MooTools\=\{version\:\'1\.12\'\}/, /11391 2009\-01\-04 13\:35\:50Z ian/ out = "1.5" when /Copyright \(C\) 2005 \- 2012 Open Source Matters/, /MooTools.More\=\{version\:\"1\.4\.0\.1\"/ out = "2.5" when /\s+ "#{tpath}#{file}", 'method' => 'GET' }) return :abort if res.nil? res.body.gsub!(/[\r|\n]/, ' ') if (res.code == 200) os = os_fingerprint(res) out = fingerprint(res) return false if not out if(out =~ /Unknown Joomla/) print_error("#{peer} - Unable to identify Joomla Version with #{file}") return false else print_good("#{peer} - Joomla Version:#{out} from: #{file} ") print_good("#{peer} - OS: #{os}") report_note( :host => ip, :port => datastore['RPORT'], :proto => 'http', :ntype => 'joomla_version', :data => out ) return true end elsif (res.code == 403) if(res.body =~ /secured with Secure Sockets Layer/ or res.body =~ /Secure Channel Required/ or res.body =~ /requires a secure connection/) vprint_status("#{ip} denied access to #{ip} (SSL Required)") elsif(res.body =~ /has a list of IP addresses that are not allowed/) vprint_status("#{ip} restricted access by IP") elsif(res.body =~ /SSL client certificate is required/) vprint_status("#{ip} requires a SSL client certificate") else vprint_status("#{ip} denied access to #{ip} #{res.code} #{res.message}") end return :abort end return false rescue OpenSSL::SSL::SSLError vprint_error("#{peer} - SSL error") return :abort rescue Errno::ENOPROTOOPT, Errno::ECONNRESET, ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::ArgumentError vprint_error("#{peer} - Unable to Connect") return :abort rescue ::Timeout::Error, ::Errno::EPIPE vprint_error("#{peer} - Timeout error") return :abort end def run_host(ip) tpath = normalize_uri(target_uri.path) if tpath[-1,1] != '/' tpath += '/' end files = [ 'language/en-GB/en-GB.xml', 'templates/system/css/system.css', 'media/system/js/mootools-more.js', 'language/en-GB/en-GB.ini', 'htaccess.txt', 'language/en-GB/en-GB.com_media.ini' ] vprint_status("#{peer} - Checking Joomla version") files.each do |file| joomla_found = check_file(tpath, file, ip) return if joomla_found == :abort break if joomla_found end end end