use base mixin in scanners

refactor the LoginScanner classes to use the
new Base mixin. Still some more cleanup to be done
bug/bundler_fix
David Maloney 2014-04-30 13:29:14 -05:00
parent 7978587428
commit 90882f803b
No known key found for this signature in database
GPG Key ID: DEDBA9DC3A913DB2
5 changed files with 132 additions and 653 deletions

View File

@ -8,147 +8,152 @@ module Metasploit
# the LoginScanner classes. All of the LoginScanners
# should include this module to establish base behaviour
module Base
extend ActiveSupport::Concern
include ActiveModel::Validations
# @!attribute connection_timeout
# @return [Fixnum] The timeout in seconds for a single SSH connection
attr_accessor :connection_timeout
# @!attribute cred_details
# @return [Array] An array of Credential objects
attr_accessor :cred_details
# @!attribute successes
# @return [Array] Array of of result objects that failed
attr_accessor :failures
# @!attribute host
# @return [String] The IP address or hostname to connect to
attr_accessor :host
# @!attribute port
# @return [Fixnum] The port to connect to
attr_accessor :port
# @!attribute proxies
# @return [String] The proxy directive to use for the socket
attr_accessor :proxies
# @!attribute ssh_socket
# @return [Net::SSH::Connection::Session] The current SSH connection
attr_accessor :ssh_socket
# @!attribute stop_on_success
# @return [Boolean] Whether the scanner should stop when it has found one working Credential
attr_accessor :stop_on_success
# @!attribute successes
# @return [Array] Array of results that successfully logged in
attr_accessor :successes
included do
# @!attribute connection_timeout
# @return [Fixnum] The timeout in seconds for a single SSH connection
attr_accessor :connection_timeout
# @!attribute cred_details
# @return [Array] An array of Credential objects
attr_accessor :cred_details
# @!attribute successes
# @return [Array] Array of of result objects that failed
attr_accessor :failures
# @!attribute host
# @return [String] The IP address or hostname to connect to
attr_accessor :host
# @!attribute port
# @return [Fixnum] The port to connect to
attr_accessor :port
# @!attribute proxies
# @return [String] The proxy directive to use for the socket
attr_accessor :proxies
# @!attribute ssh_socket
# @return [Net::SSH::Connection::Session] The current SSH connection
attr_accessor :ssh_socket
# @!attribute stop_on_success
# @return [Boolean] Whether the scanner should stop when it has found one working Credential
attr_accessor :stop_on_success
# @!attribute successes
# @return [Array] Array of results that successfully logged in
attr_accessor :successes
validates :connection_timeout,
presence: true,
numericality: {
only_integer: true,
greater_than_or_equal_to: 1
}
validates :connection_timeout,
presence: true,
numericality: {
only_integer: true,
greater_than_or_equal_to: 1
}
validates :cred_details, presence: true
validates :cred_details, presence: true
validates :host, presence: true
validates :host, presence: true
validates :port,
presence: true,
numericality: {
only_integer: true,
greater_than_or_equal_to: 1,
less_than_or_equal_to: 65535
}
validates :port,
presence: true,
numericality: {
only_integer: true,
greater_than_or_equal_to: 1,
less_than_or_equal_to: 65535
}
validates :stop_on_success,
inclusion: { in: [true, false] }
validates :stop_on_success,
inclusion: { in: [true, false] }
validate :host_address_must_be_valid
validate :host_address_must_be_valid
validate :validate_cred_details
validate :validate_cred_details
# @param attributes [Hash{Symbol => String,nil}]
def initialize(attributes={})
attributes.each do |attribute, value|
public_send("#{attribute}=", value)
# @param attributes [Hash{Symbol => String,nil}]
def initialize(attributes={})
attributes.each do |attribute, value|
public_send("#{attribute}=", value)
end
self.successes= []
self.failures=[]
end
self.successes= []
self.failures=[]
end
# This method runs all the login attempts against the target.
# It calls {attempt_login} once for each credential.
# Results are stored in {successes} and {failures}
# @return [void] There is no valid return value for this method
# @yield [result]
# @yieldparam result [Metasploit::Framework::LoginScanner::Result] The LoginScanner Result object for the attempt
# @yieldreturn [void]
def scan!
valid!
cred_details.each do |credential|
result = attempt_login(credential)
result.freeze
# This method runs all the login attempts against the target.
# It calls {attempt_login} once for each credential.
# Results are stored in {successes} and {failures}
# @return [void] There is no valid return value for this method
# @yield [result]
# @yieldparam result [Metasploit::Framework::LoginScanner::Result] The LoginScanner Result object for the attempt
# @yieldreturn [void]
def scan!
valid!
cred_details.each do |credential|
result = attempt_login(credential)
result.freeze
yield result if block_given?
yield result if block_given?
if result.success?
successes << result
break if stop_on_success
if result.success?
successes << result
break if stop_on_success
else
failures << result
end
end
end
# @raise [Metasploit::Framework::LoginScanner::Invalid] if the attributes are not valid on the scanner
def valid!
unless valid?
raise Metasploit::Framework::LoginScanner::Invalid.new(self)
end
end
private
# This method validates that the host address is both
# of a valid type and is resolveable.
# @return [void]
def host_address_must_be_valid
unless host.kind_of? String
errors.add(:host, "must be a string")
end
begin
resolved_host = ::Rex::Socket.getaddress(host, true)
if host =~ /^\d{1,3}(\.\d{1,3}){1,3}$/
unless host =~ Rex::Socket::MATCH_IPV4
errors.add(:host, "could not be resolved")
end
end
host = resolved_host
rescue
errors.add(:host, "could not be resolved")
end
end
# This method validates that the credentials supplied
# are all valid.
# @return [void]
def validate_cred_details
if cred_details.kind_of? Array
cred_details.each do |detail|
unless detail.kind_of? Metasploit::Framework::LoginScanner::Credential
errors.add(:cred_details, "has invalid element #{detail.inspect}")
next
end
unless detail.valid?
errors.add(:cred_details, "has invalid element #{detail.inspect}")
end
end
else
failures << result
errors.add(:cred_details, "must be an array")
end
end
end
# @raise [Metasploit::Framework::LoginScanner::Invalid] if the attributes are not valid on the scanner
def valid!
unless valid?
raise Metasploit::Framework::LoginScanner::Invalid.new(self)
end
end
private
# This method validates that the host address is both
# of a valid type and is resolveable.
# @return [void]
def host_address_must_be_valid
unless host.kind_of? String
errors.add(:host, "must be a string")
end
begin
resolved_host = ::Rex::Socket.getaddress(host, true)
if host =~ /^\d{1,3}(\.\d{1,3}){1,3}$/
unless host =~ Rex::Socket::MATCH_IPV4
errors.add(:host, "could not be resolved")
end
end
host = resolved_host
rescue
errors.add(:host, "could not be resolved")
end
end
# This method validates that the credentials supplied
# are all valid.
# @return [void]
def validate_cred_details
if cred_details.kind_of? Array
cred_details.each do |detail|
unless detail.kind_of? Metasploit::Framework::LoginScanner::Credential
errors.add(:cred_details, "has invalid element #{detail.inspect}")
next
end
unless detail.valid?
errors.add(:cred_details, "has invalid element #{detail.inspect}")
end
end
else
errors.add(:cred_details, "must be an array")
end
end
end
end
end
end

View File

@ -1,5 +1,5 @@
require 'metasploit/framework/ftp/client'
require 'metasploit/framework/login_scanner'
require 'metasploit/framework/login_scanner/base'
module Metasploit
module Framework
@ -9,33 +9,15 @@ module Metasploit
# It is responsible for taking a single target, and a list of credentials
# and attempting them. It then saves the results.
class FTP
include ActiveModel::Validations
include Metasploit::Framework::LoginScanner::Base
include Metasploit::Framework::Ftp::Client
# @!attribute connection_timeout
# @return [Fixnum] The timeout in seconds for a single SSH connection
attr_accessor :connection_timeout
# @!attribute cred_details
# @return [Array] An array of Credential objects
attr_accessor :cred_details
# @!attribute successes
# @return [Array] Array of of result objects that failed
attr_accessor :failures
# @!attribute ftp_timeout
# @return [Fixnum] The timeout in seconds to wait for a response to an FTP command
attr_accessor :ftp_timeout
# @!attribute host
# @return [String] The IP address or hostname to connect to
attr_accessor :host
# @!attribute max_send_size
# @return [Fixnum] The max size of the data to encapsulate in a single packet
attr_accessor :max_send_size
# @!attribute port
# @return [Fixnum] The port to connect to
attr_accessor :port
# @!attribute proxies
# @return [String] The proxy directive to use for the socket
attr_accessor :proxies
# @!attribute send_delay
# @return [Fixnum] The delay between sending packets
attr_accessor :send_delay
@ -45,22 +27,6 @@ module Metasploit
# @!attribute ssl_version
# @return [String] The version of SSL to implement
attr_accessor :ssl_version
# @!attribute stop_on_success
# @return [Boolean] Whether the scanner should stop when it has found one working Credential
attr_accessor :stop_on_success
# @!attribute successes
# @return [Array] Array of results that successfully logged in
attr_accessor :successes
validates :connection_timeout,
presence: true,
numericality: {
only_integer: true,
greater_than_or_equal_to: 1
}
validates :cred_details, presence: true
validates :ftp_timeout,
presence: true,
@ -69,8 +35,6 @@ module Metasploit
greater_than_or_equal_to: 1
}
validates :host, presence: true
validates :max_send_size,
presence: true,
numericality: {
@ -78,14 +42,6 @@ module Metasploit
greater_than_or_equal_to: 0
}
validates :port,
presence: true,
numericality: {
only_integer: true,
greater_than_or_equal_to: 1,
less_than_or_equal_to: 65535
}
validates :send_delay,
presence: true,
numericality: {
@ -93,13 +49,6 @@ module Metasploit
greater_than_or_equal_to: 0
}
validates :stop_on_success,
inclusion: { in: [true, false] }
validate :host_address_must_be_valid
validate :validate_cred_details
# @param attributes [Hash{Symbol => String,nil}]
def initialize(attributes={})
@ -140,60 +89,8 @@ module Metasploit
end
# This method runs all the login attempts against the target.
# It calls {attempt_login} once for each credential.
# Results are stored in {successes} and {failures}
# @return [void] There is no valid return value for this method
# @yield [result]
# @yieldparam result [Metasploit::Framework::LoginScanner::Result] The LoginScanner Result object for the attempt
# @yieldreturn [void]
def scan!
valid!
cred_details.each do |credential|
result = attempt_login(credential)
result.freeze
yield result if block_given?
if result.success?
successes << result
break if stop_on_success
else
failures << result
end
end
end
# @raise [Metasploit::Framework::LoginScanner::Invalid] if the attributes are not valid on the scanner
def valid!
unless valid?
raise Metasploit::Framework::LoginScanner::Invalid.new(self)
end
end
private
# This method validates that the host address is both
# of a valid type and is resolveable.
# @return [void]
def host_address_must_be_valid
unless host.kind_of? String
errors.add(:host, "must be a string")
end
begin
resolved_host = ::Rex::Socket.getaddress(host, true)
if host =~ /^\d{1,3}(\.\d{1,3}){1,3}$/
unless host =~ Rex::Socket::MATCH_IPV4
errors.add(:host, "could not be resolved")
end
end
host = resolved_host
rescue
errors.add(:host, "could not be resolved")
end
end
def chost
'0.0.0.0'
end
@ -210,27 +107,6 @@ module Metasploit
port
end
# This method validates that the credentials supplied
# are all valid.
# @return [void]
def validate_cred_details
if cred_details.kind_of? Array
cred_details.each do |detail|
unless detail.kind_of? Metasploit::Framework::LoginScanner::Credential
errors.add(:cred_details, "has invalid element #{detail.inspect}")
next
end
unless detail.valid?
errors.add(:cred_details, "has invalid element #{detail.inspect}")
end
end
else
errors.add(:cred_details, "must be an array")
end
end
end
end

View File

@ -1,5 +1,5 @@
require 'snmp'
require 'metasploit/framework/login_scanner'
require 'metasploit/framework/login_scanner/base'
module Metasploit
module Framework
@ -9,69 +9,7 @@ module Metasploit
# It is responsible for taking a single target, and a list of credentials
# and attempting them. It then saves the results.
class SNMP
include ActiveModel::Validations
# @!attribute connection_timeout
# @return [Fixnum] The timeout in seconds for a single SSH connection
attr_accessor :connection_timeout
# @!attribute cred_details
# @return [Array] An array of Credential objects
attr_accessor :cred_details
# @!attribute successes
# @return [Array] Array of of result objects that failed
attr_accessor :failures
# @!attribute host
# @return [String] The IP address or hostname to connect to
attr_accessor :host
# @!attribute port
# @return [Fixnum] The port to connect to
attr_accessor :port
# @!attribute proxies
# @return [String] The proxy directive to use for the socket
attr_accessor :proxies
# @!attribute ssh_socket
# @return [Net::SSH::Connection::Session] The current SSH connection
attr_accessor :stop_on_success
# @!attribute successes
# @return [Array] Array of results that successfully logged in
attr_accessor :successes
validates :connection_timeout,
presence: true,
numericality: {
only_integer: true,
greater_than_or_equal_to: 1
}
validates :cred_details, presence: true
validates :host, presence: true
validates :port,
presence: true,
numericality: {
only_integer: true,
greater_than_or_equal_to: 1,
less_than_or_equal_to: 65535
}
validates :stop_on_success,
inclusion: { in: [true, false] }
validate :host_address_must_be_valid
validate :validate_cred_details
# @param attributes [Hash{Symbol => String,nil}]
def initialize(attributes={})
attributes.each do |attribute, value|
public_send("#{attribute}=", value)
end
self.successes= []
self.failures=[]
end
include Metasploit::Framework::LoginScanner::Base
# This method attempts a single login with a single credential against the target
# @param credential [Credential] The credential object to attmpt to login with
@ -113,59 +51,8 @@ module Metasploit
::Metasploit::Framework::LoginScanner::Result.new(result_options)
end
# This method runs all the login attempts against the target.
# It calls {attempt_login} once for each credential.
# Results are stored in {successes} and {failures}
# @return [void] There is no valid return value for this method
# @yield [result]
# @yieldparam result [Metasploit::Framework::LoginScanner::Result] The LoginScanner Result object for the attempt
# @yieldreturn [void]
def scan!
valid!
cred_details.each do |credential|
result = attempt_login(credential)
result.freeze
yield result if block_given?
if result.success?
successes << result
break if stop_on_success
else
failures << result
end
end
end
# @raise [Metasploit::Framework::LoginScanner::Invalid] if the attributes are not valid on the scanner
def valid!
unless valid?
raise Metasploit::Framework::LoginScanner::Invalid.new(self)
end
end
private
# This method validates that the host address is both
# of a valid type and is resolveable.
# @return [void]
def host_address_must_be_valid
unless host.kind_of? String
errors.add(:host, "must be a string")
end
begin
resolved_host = ::Rex::Socket.getaddress(host, true)
if host =~ /^\d{1,3}(\.\d{1,3}){1,3}$/
unless host =~ Rex::Socket::MATCH_IPV4
errors.add(:host, "could not be resolved")
end
end
host = resolved_host
rescue
errors.add(:host, "could not be resolved")
end
end
# This method takes an snmp client and tests whether
# it has read access to the remote system. It checks
# the sysDescr oid to use as proof
@ -201,28 +88,6 @@ module Metasploit
end
# This method validates that the credentials supplied
# are all valid.
# @return [void]
def validate_cred_details
if cred_details.kind_of? Array
cred_details.each do |detail|
unless detail.kind_of? Metasploit::Framework::LoginScanner::Credential
errors.add(:cred_details, "has invalid element #{detail.inspect}")
next
end
unless detail.valid?
errors.add(:cred_details, "has invalid element #{detail.inspect}")
end
end
else
errors.add(:cred_details, "must be an array")
end
end
end
end

View File

@ -1,5 +1,5 @@
require 'net/ssh'
require 'metasploit/framework/login_scanner'
require 'metasploit/framework/login_scanner/base'
module Metasploit
module Framework
@ -9,7 +9,7 @@ module Metasploit
# It is responsible for taking a single target, and a list of credentials
# and attempting them. It then saves the results.
class SSH
include ActiveModel::Validations
include Metasploit::Framework::LoginScanner::Base
#
# CONSTANTS
@ -23,78 +23,16 @@ module Metasploit
:fatal
]
# @!attribute connection_timeout
# @return [Fixnum] The timeout in seconds for a single SSH connection
attr_accessor :connection_timeout
# @!attribute cred_details
# @return [Array] An array of Credential objects
attr_accessor :cred_details
# @!attribute successes
# @return [Array] Array of of result objects that failed
attr_accessor :failures
# @!attribute host
# @return [String] The IP address or hostname to connect to
attr_accessor :host
# @!attribute port
# @return [Fixnum] The port to connect to
attr_accessor :port
# @!attribute proxies
# @return [String] The proxy directive to use for the socket
attr_accessor :proxies
# @!attribute ssh_socket
# @return [Net::SSH::Connection::Session] The current SSH connection
attr_accessor :ssh_socket
# @!attribute stop_on_success
# @return [Boolean] Whether the scanner should stop when it has found one working Credential
attr_accessor :stop_on_success
# @!attribute successes
# @return [Array] Array of results that successfully logged in
attr_accessor :successes
# @!attribute verbosity
# The verbosity level for the SSH client.
#
# @return [Symbol] An element of {VERBOSITIES}.
attr_accessor :verbosity
validates :connection_timeout,
presence: true,
numericality: {
only_integer: true,
greater_than_or_equal_to: 1
}
validates :cred_details, presence: true
validates :host, presence: true
validates :port,
presence: true,
numericality: {
only_integer: true,
greater_than_or_equal_to: 1,
less_than_or_equal_to: 65535
}
validates :stop_on_success,
inclusion: { in: [true, false] }
validates :verbosity,
presence: true,
inclusion: { in: VERBOSITIES }
validate :host_address_must_be_valid
validate :validate_cred_details
# @param attributes [Hash{Symbol => String,nil}]
def initialize(attributes={})
attributes.each do |attribute, value|
public_send("#{attribute}=", value)
end
self.successes= []
self.failures=[]
end
# 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
@ -142,37 +80,6 @@ module Metasploit
end
# This method runs all the login attempts against the target.
# It calls {attempt_login} once for each credential.
# Results are stored in {successes} and {failures}
# @return [void] There is no valid return value for this method
# @yield [result]
# @yieldparam result [Metasploit::Framework::LoginScanner::Result] The LoginScanner Result object for the attempt
# @yieldreturn [void]
def scan!
valid!
cred_details.each do |credential|
result = attempt_login(credential)
result.freeze
yield result if block_given?
if result.success?
successes << result
break if stop_on_success
else
failures << result
end
end
end
# @raise [Metasploit::Framework::LoginScanner::Invalid] if the attributes are not valid on the scanner
def valid!
unless valid?
raise Metasploit::Framework::LoginScanner::Invalid.new(self)
end
end
private
# This method attempts to gather proof that we successfuly logged in.
@ -198,47 +105,6 @@ module Metasploit
proof
end
# This method validates that the host address is both
# of a valid type and is resolveable.
# @return [void]
def host_address_must_be_valid
unless host.kind_of? String
errors.add(:host, "must be a string")
end
begin
resolved_host = ::Rex::Socket.getaddress(host, true)
if host =~ /^\d{1,3}(\.\d{1,3}){1,3}$/
unless host =~ Rex::Socket::MATCH_IPV4
errors.add(:host, "could not be resolved")
end
end
host = resolved_host
rescue
errors.add(:host, "could not be resolved")
end
end
# This method validates that the credentials supplied
# are all valid.
# @return [void]
def validate_cred_details
if cred_details.kind_of? Array
cred_details.each do |detail|
unless detail.kind_of? Metasploit::Framework::LoginScanner::Credential
errors.add(:cred_details, "has invalid element #{detail.inspect}")
next
end
unless detail.valid?
errors.add(:cred_details, "has invalid element #{detail.inspect}")
end
end
else
errors.add(:cred_details, "must be an array")
end
end
end
end

View File

@ -1,5 +1,5 @@
require 'net/ssh'
require 'metasploit/framework/login_scanner'
require 'metasploit/framework/login_scanner/base'
module Metasploit
module Framework
@ -10,7 +10,7 @@ module Metasploit
# and attempting them. It then saves the results. In this case it is expecting
# SSH private keys for the private credential.
class SSHKey
include ActiveModel::Validations
include Metasploit::Framework::LoginScanner::Base
#
# CONSTANTS
@ -24,77 +24,16 @@ module Metasploit
:fatal
]
# @!attribute connection_timeout
# @return [Fixnum] The timeout in seconds for a single SSH connection
attr_accessor :connection_timeout
# @!attribute cred_details
# @return [Array] An array of Credential objects
attr_accessor :cred_details
# @!attribute successes
# @return [Array] Array of of result objects that failed
attr_accessor :failures
# @!attribute host
# @return [String] The IP address or hostname to connect to
attr_accessor :host
# @!attribute port
# @return [Fixnum] The port to connect to
attr_accessor :port
# @!attribute proxies
# @return [String] The proxy directive to use for the socket
attr_accessor :proxies
# @!attribute ssh_socket
# @return [Net::SSH::Connection::Session] The current SSH connection
attr_accessor :ssh_socket
# @!attribute stop_on_success
# @return [Boolean] Whether the scanner should stop when it has found one working Credential
attr_accessor :stop_on_success
# @!attribute successes
# @return [Array] Array of results that successfully logged in
attr_accessor :successes
# @!attribute verbosity
# The verbosity level for the SSH client.
#
# @return [Symbol] An element of {VERBOSITIES}.
attr_accessor :verbosity
validates :connection_timeout,
presence: true,
numericality: {
only_integer: true,
greater_than_or_equal_to: 1
}
validates :cred_details, presence: true
validates :host, presence: true
validates :port,
presence: true,
numericality: {
only_integer: true,
greater_than_or_equal_to: 1,
less_than_or_equal_to: 65535
}
validates :stop_on_success,
inclusion: { in: [true, false] }
validates :verbosity,
presence: true,
inclusion: { in: VERBOSITIES }
validate :host_address_must_be_valid
validate :validate_cred_details
# @param attributes [Hash{Symbol => String,nil}]
def initialize(attributes={})
attributes.each do |attribute, value|
public_send("#{attribute}=", value)
end
self.successes= []
self.failures=[]
end
# This method attempts a single login with a single credential against the target
# @param credential [Credential] The credential object to attmpt to login with
@ -143,37 +82,6 @@ module Metasploit
end
# This method runs all the login attempts against the target.
# It calls {attempt_login} once for each credential.
# Results are stored in {successes} and {failures}
# @return [void] There is no valid return value for this method
# @yield [result]
# @yieldparam result [Metasploit::Framework::LoginScanner::Result] The LoginScanner Result object for the attempt
# @yieldreturn [void]
def scan!
valid!
cred_details.each do |credential|
result = attempt_login(credential)
result.freeze
yield result if block_given?
if result.success?
successes << result
break if stop_on_success
else
failures << result
end
end
end
# @raise [Metasploit::Framework::LoginScanner::Invalid] if the attributes are not valid on the scanner
def valid!
unless valid?
raise Metasploit::Framework::LoginScanner::Invalid.new(self)
end
end
private
# This method attempts to gather proof that we successfuly logged in.
@ -199,47 +107,6 @@ module Metasploit
proof
end
# This method validates that the host address is both
# of a valid type and is resolveable.
# @return [void]
def host_address_must_be_valid
unless host.kind_of? String
errors.add(:host, "must be a string")
end
begin
resolved_host = ::Rex::Socket.getaddress(host, true)
if host =~ /^\d{1,3}(\.\d{1,3}){1,3}$/
unless host =~ Rex::Socket::MATCH_IPV4
errors.add(:host, "could not be resolved")
end
end
host = resolved_host
rescue
errors.add(:host, "could not be resolved")
end
end
# This method validates that the credentials supplied
# are all valid.
# @return [void]
def validate_cred_details
if cred_details.kind_of? Array
cred_details.each do |detail|
unless detail.kind_of? Metasploit::Framework::LoginScanner::Credential
errors.add(:cred_details, "has invalid element #{detail.inspect}")
next
end
unless detail.valid?
errors.add(:cred_details, "has invalid element #{detail.inspect}")
end
end
else
errors.add(:cred_details, "must be an array")
end
end
end
end