diff --git a/lib/metasploit/framework/login_scanner.rb b/lib/metasploit/framework/login_scanner.rb index be229eac7b..d39966273f 100644 --- a/lib/metasploit/framework/login_scanner.rb +++ b/lib/metasploit/framework/login_scanner.rb @@ -6,16 +6,25 @@ module Metasploit # LoginScanners are the classes that provide functionality for testing # authentication against various different protocols and mechanisms. module LoginScanner - # Make sure Base is loaded before any of the others - require 'metasploit/framework/login_scanner/base' - - dir = File.expand_path("../login_scanner/", __FILE__) - Dir.entries(dir).each do |f| - f = File.join(dir, f) - require f if File.file?(f) - end + # Gather a list of LoginScanner classes that can potentially be + # used for a give `service`. + # + # @note This + # @param service [Mdm::Service,#port,#name] + # @return [Array] def self.classes_for_service(service) + + unless @required + # Make sure we've required all the scanner classes + dir = File.expand_path("../login_scanner/", __FILE__) + Dir.entries(dir).each do |f| + f = File.join(dir, f) + require f if File.file?(f) + end + @required = true + end + self.constants.map{|sym| const_get(sym)}.select do |const| next unless const.kind_of?(Class) diff --git a/lib/metasploit/framework/login_scanner/afp.rb b/lib/metasploit/framework/login_scanner/afp.rb index faa5985c48..33a7a4fa5a 100644 --- a/lib/metasploit/framework/login_scanner/afp.rb +++ b/lib/metasploit/framework/login_scanner/afp.rb @@ -15,6 +15,11 @@ module Metasploit include Metasploit::Framework::Tcp::Client include Metasploit::Framework::AFP::Client + DEFAULT_PORT = 548 + LIKELY_PORTS = [ DEFAULT_PORT ] + LIKELY_SERVICE_NAMES = [ "afp" ] + PRIVATE_TYPES = [ :password ] + # @!attribute login_timeout # @return [Integer] Number of seconds to wait before giving up attr_accessor :login_timeout @@ -33,7 +38,7 @@ module Metasploit end def set_sane_defaults - self.port = 548 if self.port.nil? + self.port = DEFAULT_PORT if self.port.nil? self.max_send_size = 0 if self.max_send_size.nil? self.send_delay = 0 if self.send_delay.nil? end diff --git a/lib/metasploit/framework/login_scanner/axis2.rb b/lib/metasploit/framework/login_scanner/axis2.rb index 284701f544..cd2c01891e 100644 --- a/lib/metasploit/framework/login_scanner/axis2.rb +++ b/lib/metasploit/framework/login_scanner/axis2.rb @@ -9,6 +9,10 @@ module Metasploit class Axis2 < HTTP DEFAULT_PORT = 8080 + # Inherit LIKELY_PORTS and LIKELY_SERVICE_NAMES from HTTP + + CAN_GET_SESSION = true + PRIVATE_TYPES = [ :password ] # (see Base#attempt_login) def attempt_login(credential) diff --git a/lib/metasploit/framework/login_scanner/db2.rb b/lib/metasploit/framework/login_scanner/db2.rb index cfc17c4652..76ccbc3196 100644 --- a/lib/metasploit/framework/login_scanner/db2.rb +++ b/lib/metasploit/framework/login_scanner/db2.rb @@ -13,6 +13,12 @@ module Metasploit include Metasploit::Framework::LoginScanner::RexSocket include Metasploit::Framework::Tcp::Client + DEFAULT_PORT = 50000 + LIKELY_PORTS = [ DEFAULT_PORT ] + # @todo XXX + LIKELY_SERVICE_NAMES = [ ] + PRIVATE_TYPES = [ :password ] + # @see Base#attempt_login def attempt_login(credential) result_options = { @@ -88,6 +94,7 @@ module Metasploit # This method sets the sane defaults for things # like timeouts and TCP evasion options def set_sane_defaults + self.port ||= DEFAULT_PORT self.max_send_size ||= 0 self.send_delay ||= 0 self.ssl ||= false @@ -120,4 +127,4 @@ module Metasploit end end -end \ No newline at end of file +end diff --git a/lib/metasploit/framework/login_scanner/ftp.rb b/lib/metasploit/framework/login_scanner/ftp.rb index 4b1213c49a..7a25da2467 100644 --- a/lib/metasploit/framework/login_scanner/ftp.rb +++ b/lib/metasploit/framework/login_scanner/ftp.rb @@ -14,6 +14,11 @@ module Metasploit include Metasploit::Framework::LoginScanner::RexSocket include Metasploit::Framework::Ftp::Client + DEFAULT_PORT = 21 + LIKELY_PORTS = [ DEFAULT_PORT, 2121 ] + LIKELY_SERVICE_NAMES = [ 'ftp' ] + PRIVATE_TYPES = [ :password ] + # @!attribute ftp_timeout # @return [Fixnum] The timeout in seconds to wait for a response to an FTP command attr_accessor :ftp_timeout @@ -56,6 +61,7 @@ module Metasploit # This method sets the sane defaults for things # like timeouts and TCP evasion options def set_sane_defaults + self.port = DEFAULT_PORT if self.port.nil? self.max_send_size = 0 if self.max_send_size.nil? self.send_delay = 0 if self.send_delay.nil? self.ftp_timeout = 16 if self.ftp_timeout.nil? diff --git a/lib/metasploit/framework/login_scanner/http.rb b/lib/metasploit/framework/login_scanner/http.rb index 7be9b341bf..ccf2163a38 100644 --- a/lib/metasploit/framework/login_scanner/http.rb +++ b/lib/metasploit/framework/login_scanner/http.rb @@ -14,6 +14,7 @@ module Metasploit LIKELY_PORTS = [ 80, 443, 8000, 8080 ] LIKELY_SERVICE_NAMES = [ 'http', 'https' ] + PRIVATE_TYPES = [ :password ] DEFAULT_PORT = 80 DEFAULT_SSL_PORT = 443 diff --git a/lib/metasploit/framework/login_scanner/mssql.rb b/lib/metasploit/framework/login_scanner/mssql.rb index c00d432417..f65db25b8d 100644 --- a/lib/metasploit/framework/login_scanner/mssql.rb +++ b/lib/metasploit/framework/login_scanner/mssql.rb @@ -16,6 +16,13 @@ module Metasploit include Metasploit::Framework::LoginScanner::NTLM include Metasploit::Framework::MSSQL::Client + # Lifted from lib/msf/core/exploit/mssql.rb + LIKELY_PORTS = [ 1433, 1434, 1435, 14330, 2533, 9152, 2638 ] + LIKELY_SERVICE_NAMES = [ 'ms-sql-s', 'ms-sql2000', 'sybase' ] + PRIVATE_TYPES = [ :password, :ntlm_hash ] + + DEFUAULT_PORT = 1433 + # @!attribute windows_authentication # @return [Boolean] Whether to use Windows Authentication instead of SQL Server Auth. attr_accessor :windows_authentication @@ -44,6 +51,7 @@ module Metasploit private def set_sane_defaults + self.port = DEFAULT_PORT self.port.nil? self.max_send_size = 0 if self.max_send_size.nil? self.send_delay = 0 if self.send_delay.nil? self.send_lm = true if self.send_lm.nil? diff --git a/lib/metasploit/framework/login_scanner/mysql.rb b/lib/metasploit/framework/login_scanner/mysql.rb index 69e2ad8c58..0e8828d3f2 100644 --- a/lib/metasploit/framework/login_scanner/mysql.rb +++ b/lib/metasploit/framework/login_scanner/mysql.rb @@ -15,6 +15,11 @@ module Metasploit include Metasploit::Framework::LoginScanner::RexSocket include Metasploit::Framework::Tcp::Client + DEFAULT_PORT = 3306 + LIKELY_PORTS = [ 3306 ] + LIKELY_SERVICE_NAMES = [ 'mysql' ] + PRIVATE_TYPES = [ :password ] + def attempt_login(credential) result_options = { credential: credential @@ -72,6 +77,7 @@ module Metasploit # This method sets the sane defaults for things # like timeouts and TCP evasion options def set_sane_defaults + self.port = DEFAULT_PORT self.port.nil? self.max_send_size = 0 if self.max_send_size.nil? self.send_delay = 0 if self.send_delay.nil? end @@ -80,4 +86,4 @@ module Metasploit end end -end \ No newline at end of file +end diff --git a/lib/metasploit/framework/login_scanner/pop3.rb b/lib/metasploit/framework/login_scanner/pop3.rb index 738ffc8fb9..c3bde533df 100644 --- a/lib/metasploit/framework/login_scanner/pop3.rb +++ b/lib/metasploit/framework/login_scanner/pop3.rb @@ -14,6 +14,11 @@ module Metasploit include Metasploit::Framework::LoginScanner::RexSocket include Metasploit::Framework::Tcp::Client + DEFAULT_PORT = 110 + LIKELY_PORTS = [ 110, 995 ] + LIKELY_SERVICE_NAMES = [ 'pop3', 'pop3s' ] + PRIVATE_TYPES = [ :password ] + # This method attempts a single login with a single credential against the target # @param credential [Credential] The credential object to attempt to login with # @return [Metasploit::Framework::LoginScanner::Result] The LoginScanner Result object @@ -62,12 +67,12 @@ module Metasploit # (see Base#set_sane_defaults) def set_sane_defaults + self.port = DEFAULT_PORT if self.port.nil? self.max_send_size ||= 0 self.send_delay ||= 0 - self.port ||= 110 end - end + end end end diff --git a/lib/metasploit/framework/login_scanner/postgres.rb b/lib/metasploit/framework/login_scanner/postgres.rb index 79a6c334e9..ac49f273a5 100644 --- a/lib/metasploit/framework/login_scanner/postgres.rb +++ b/lib/metasploit/framework/login_scanner/postgres.rb @@ -11,6 +11,12 @@ module Metasploit class Postgres include Metasploit::Framework::LoginScanner::Base + DEFAULT_PORT = 5432 + + LIKELY_PORTS = [ DEFAULT_PORT ] + LIKELY_SERVICE_NAMES = [ 'postgres' ] + PRIVATE_TYPES = [ :password ] + # This method attempts a single login with a single credential against the target # @param credential [Credential] The credential object to attmpt to login with # @return [Metasploit::Framework::LoginScanner::Result] The LoginScanner Result object @@ -62,6 +68,10 @@ module Metasploit end end + def set_sane_defaults + self.port = DEFAULT_PORT if self.port.nil? + end + end end -end \ No newline at end of file +end diff --git a/lib/metasploit/framework/login_scanner/smb.rb b/lib/metasploit/framework/login_scanner/smb.rb index 2597e89c82..991ba78722 100644 --- a/lib/metasploit/framework/login_scanner/smb.rb +++ b/lib/metasploit/framework/login_scanner/smb.rb @@ -17,8 +17,10 @@ module Metasploit include Metasploit::Framework::LoginScanner::RexSocket include Metasploit::Framework::LoginScanner::NTLM + CAN_GET_SESSION = true LIKELY_PORTS = [ 139, 445 ] LIKELY_SERVICE_NAMES = [ "smb" ] + PRIVATE_TYPES = [ :password, :ntlm_hash ] module StatusCodes CORRECT_CREDENTIAL_STATUS_CODES = [ diff --git a/lib/metasploit/framework/login_scanner/snmp.rb b/lib/metasploit/framework/login_scanner/snmp.rb index 80b616e6df..6da0af11a6 100644 --- a/lib/metasploit/framework/login_scanner/snmp.rb +++ b/lib/metasploit/framework/login_scanner/snmp.rb @@ -11,6 +11,11 @@ module Metasploit class SNMP include Metasploit::Framework::LoginScanner::Base + DEFAULT_PORT = 161 + LIKELY_PORTS = [ 161, 162 ] + LIKELY_SERVICE_NAMES = [ 'snmp' ] + PRIVATE_TYPES = [ :password ] + # This method attempts a single login with a single credential against the target # @param credential [Credential] The credential object to attmpt to login with # @return [Metasploit::Framework::LoginScanner::Result] The LoginScanner Result object @@ -72,6 +77,7 @@ module Metasploit # if the user did not set it. def set_sane_defaults self.connection_timeout = 2 if self.connection_timeout.nil? + self.port = DEFAULT_PORT if self.port.nil? end # This method takes an snmp client and tests whether diff --git a/lib/metasploit/framework/login_scanner/ssh.rb b/lib/metasploit/framework/login_scanner/ssh.rb index 2f168534dc..745a5de038 100644 --- a/lib/metasploit/framework/login_scanner/ssh.rb +++ b/lib/metasploit/framework/login_scanner/ssh.rb @@ -15,6 +15,12 @@ module Metasploit # CONSTANTS # + CAN_GET_SESSION = true + DEFAULT_PORT = 22 + LIKELY_PORTS = [ DEFAULT_PORT ] + LIKELY_SERVICE_NAMES = [ 'ssh' ] + PRIVATE_TYPES = [ :password ] + VERBOSITIES = [ :debug, :info, @@ -105,6 +111,7 @@ module Metasploit def set_sane_defaults self.connection_timeout = 30 if self.connection_timeout.nil? + self.port = DEFAULT_PORT if self.port.nil? self.verbosity = :fatal if self.verbosity.nil? end diff --git a/lib/metasploit/framework/login_scanner/ssh_key.rb b/lib/metasploit/framework/login_scanner/ssh_key.rb index 1e5d025b5e..b6c458e987 100644 --- a/lib/metasploit/framework/login_scanner/ssh_key.rb +++ b/lib/metasploit/framework/login_scanner/ssh_key.rb @@ -16,6 +16,12 @@ module Metasploit # CONSTANTS # + CAN_GET_SESSION = true + DEFAULT_PORT = 22 + LIKELY_PORTS = [ DEFAULT_PORT ] + LIKELY_SERVICE_NAMES = [ 'ssh' ] + PRIVATE_TYPES = [ :ssh_key ] + VERBOSITIES = [ :debug, :info, @@ -110,6 +116,7 @@ module Metasploit end def set_sane_defaults + self.port = DEFAULT_PORT if self.port.nil? self.connection_timeout = 30 if self.connection_timeout.nil? self.verbosity = :fatal if self.verbosity.nil? end diff --git a/lib/metasploit/framework/login_scanner/telnet.rb b/lib/metasploit/framework/login_scanner/telnet.rb index b71582cfec..22626954b7 100644 --- a/lib/metasploit/framework/login_scanner/telnet.rb +++ b/lib/metasploit/framework/login_scanner/telnet.rb @@ -13,6 +13,12 @@ module Metasploit include Metasploit::Framework::LoginScanner::RexSocket include Metasploit::Framework::Telnet::Client + CAN_GET_SESSION = true + DEFAULT_PORT = 23 + LIKELY_PORTS = [ DEFAULT_PORT ] + LIKELY_SERVICE_NAMES = [ 'telnet' ] + PRIVATE_TYPES = [ :password ] + # @!attribute verbosity # The timeout to wait for the telnet banner. # @@ -90,6 +96,7 @@ module Metasploit # like timeouts and TCP evasion options def set_sane_defaults self.max_send_size ||= 0 + self.port ||= DEFAULT_PORT self.send_delay ||= 0 self.banner_timeout ||= 25 self.telnet_timeout ||= 10 @@ -101,4 +108,4 @@ module Metasploit end end end -end \ No newline at end of file +end diff --git a/lib/metasploit/framework/login_scanner/tomcat.rb b/lib/metasploit/framework/login_scanner/tomcat.rb index 4fa8c9af7c..f20b4b6568 100644 --- a/lib/metasploit/framework/login_scanner/tomcat.rb +++ b/lib/metasploit/framework/login_scanner/tomcat.rb @@ -8,7 +8,9 @@ module Metasploit # Tomcat Manager login scanner class Tomcat < HTTP + CAN_GET_SESSION = true DEFAULT_PORT = 8180 + PRIVATE_TYPES = [ :password ] # (see Base#set_sane_defaults) def set_sane_defaults diff --git a/lib/metasploit/framework/login_scanner/vnc.rb b/lib/metasploit/framework/login_scanner/vnc.rb index d949137795..bc94393cf3 100644 --- a/lib/metasploit/framework/login_scanner/vnc.rb +++ b/lib/metasploit/framework/login_scanner/vnc.rb @@ -19,6 +19,10 @@ module Metasploit # CONSTANTS # + LIKELY_PORTS = (5900..5910).to_a + LIKELY_SERVICE_NAMES = [ 'vnc' ] + PRIVATE_TYPES = [ :password ] + # Error indicating retry should occur for UltraVNC ULTRA_VNC_RETRY_ERROR = 'connection has been rejected' # Error indicating retry should occur for VNC 4 Server @@ -85,6 +89,7 @@ module Metasploit # This method sets the sane defaults for things # like timeouts and TCP evasion options def set_sane_defaults + self.port ||= 5900 self.max_send_size ||= 0 self.send_delay ||= 0 end @@ -112,4 +117,4 @@ module Metasploit end end -end \ No newline at end of file +end diff --git a/lib/metasploit/framework/login_scanner/winrm.rb b/lib/metasploit/framework/login_scanner/winrm.rb index aca33115d5..d6c131e2e9 100644 --- a/lib/metasploit/framework/login_scanner/winrm.rb +++ b/lib/metasploit/framework/login_scanner/winrm.rb @@ -19,6 +19,8 @@ module Metasploit # that before v1.1, the default was 443 DEFAULT_SSL_PORT = 5986 + PRIVATE_TYPES = [ :password ] + validates :method, inclusion: { in: ["POST"] } # (see Base#set_sane_defaults) @@ -30,7 +32,7 @@ module Metasploit end # The method *must* be "POST", so don't let the user change it - # @raise [RuntimeError] + # @raise [RuntimeError] Unconditionally def method=(_) raise RuntimeError, "Method must be POST for WinRM" end diff --git a/spec/lib/metasploit/framework/login_scanner_spec.rb b/spec/lib/metasploit/framework/login_scanner_spec.rb index b981754c11..7b22109bf8 100644 --- a/spec/lib/metasploit/framework/login_scanner_spec.rb +++ b/spec/lib/metasploit/framework/login_scanner_spec.rb @@ -1,5 +1,8 @@ require 'spec_helper' require 'metasploit/framework/login_scanner' +require 'metasploit/framework/login_scanner/http' +require 'metasploit/framework/login_scanner/smb' +require 'metasploit/framework/login_scanner/vnc' describe Metasploit::Framework::LoginScanner do @@ -27,6 +30,7 @@ describe Metasploit::Framework::LoginScanner do it { should include Metasploit::Framework::LoginScanner::SMB } it { should_not include Metasploit::Framework::LoginScanner::HTTP } + it { should_not include Metasploit::Framework::LoginScanner::VNC } end end @@ -35,6 +39,7 @@ describe Metasploit::Framework::LoginScanner do it { should include Metasploit::Framework::LoginScanner::HTTP } it { should_not include Metasploit::Framework::LoginScanner::SMB } + it { should_not include Metasploit::Framework::LoginScanner::VNC } end [ 80, 8080, 8000, 443 ].each do |foo| @@ -42,6 +47,8 @@ describe Metasploit::Framework::LoginScanner do let(:port) { foo } it { should include Metasploit::Framework::LoginScanner::HTTP } + it { should include Metasploit::Framework::LoginScanner::Axis2 } + it { should include Metasploit::Framework::LoginScanner::Tomcat } it { should_not include Metasploit::Framework::LoginScanner::SMB } end end