fix up some more specs

some spec cleanup and added basic specs
to the HTTP LoginScanner
bug/bundler_fix
David Maloney 2014-05-01 12:10:51 -05:00
parent 1a5abc49d1
commit 5e6f57f711
No known key found for this signature in database
GPG Key ID: DEDBA9DC3A913DB2
4 changed files with 52 additions and 116 deletions

View File

@ -1,5 +1,6 @@
require 'rex/proto/http'
require 'metasploit/framework/login_scanner'
require 'metasploit/framework/login_scanner/base'
require 'metasploit/framework/login_scanner/rex_socket'
module Metasploit
module Framework
@ -8,75 +9,17 @@ module Metasploit
# HTTP-specific login scananer.
#
class HTTP
include ActiveModel::Validations
include Metasploit::Framework::LoginScanner::Base
include Metasploit::Framework::LoginScanner::RexSocket
# @!attribute connection_timeout
# @return [Numeric] The timeout in seconds for a single connection
attr_accessor :connection_timeout
# @!attribute cred_details
# @return [Array] An array of {Credential} objects
attr_accessor :cred_details
# @!attribute failures
# @return [Array] Array 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 ssl
# @return [Boolean] Whether this client makes SSL connections
attr_accessor :ssl
# @!attribute ssl_version
# @return [Symbol] The version of SSL/TLS to use when connecting
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 {Result} objects that succeded
attr_accessor :successes
# @!attribute uri
# @return [String] The path and query string on the server to
# authenticate to.
attr_accessor :uri
validates :connection_timeout, presence: true
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: 0xffff
}
validates :uri, presence: true, length: { minimum: 1 }
# @param attributes [Hash{Symbol => String,nil}]
def initialize(attributes = {})
attributes.each do |attribute, value|
public_send("#{attribute}=", value)
end
self.successes = []
self.failures = []
end
# Attempt a single login with a single credential against the target.
#
# @param credential [Credential] The credential object to attempt to
@ -126,39 +69,13 @@ module Metasploit
Result.new(result_opts)
end
# Run all the login attempts against the target.
#
# This method calls {#attempt_login} once for each credential in
# {#cred_details}. Results are stored in {#successes} and {#failures}.
# If a block is given, each result will be yielded as we go.
#
# @yieldparam result [Result] The frozen {Result} object associated
# with each attempt
# @yieldreturn [void]
# @return [void]
def scan!
valid!
cred_details.each do |credential|
result = attempt_login(credential)
result.freeze
private
yield result if block_given?
if result.success?
successes << result
break if stop_on_success
else
failures << result
end
end
end
# @return [void]
# @raise [Invalid] if this scanner's attributes are not valid
def valid!
unless valid?
raise LoginScanner::Invalid.new(self)
end
# This method sets the sane defaults for things
# like timeouts and TCP evasion options
def set_sane_defaults
self.max_send_size = 0 if self.max_send_size.nil?
self.send_delay = 0 if self.send_delay.nil?
end
end

View File

@ -0,0 +1,15 @@
require 'spec_helper'
require 'metasploit/framework/login_scanner/http'
describe Metasploit::Framework::LoginScanner::HTTP do
subject(:http_scanner) { described_class.new }
it_behaves_like 'Metasploit::Framework::LoginScanner::Base'
it_behaves_like 'Metasploit::Framework::LoginScanner::RexSocket'
it { should respond_to :uri }
end

View File

@ -276,13 +276,14 @@ shared_examples_for 'Metasploit::Framework::LoginScanner::Base' do
it 'calls valid! before running' do
my_scanner = login_scanner
my_scanner.should_receive(:valid!).and_call_original
my_scanner.should_receive(:valid!)
my_scanner.should_receive(:attempt_login).at_least(:once).and_return success
my_scanner.scan!
end
it 'call attempt_login once for each cred_detail' do
my_scanner = login_scanner
my_scanner.should_receive(:valid!)
my_scanner.should_receive(:attempt_login).once.with(pub_blank).and_return success
my_scanner.should_receive(:attempt_login).once.with(pub_pub).and_return success
my_scanner.should_receive(:attempt_login).once.with(pub_pri).and_return success
@ -291,6 +292,7 @@ shared_examples_for 'Metasploit::Framework::LoginScanner::Base' do
it 'adds the failed results to the failures attribute' do
my_scanner = login_scanner
my_scanner.should_receive(:valid!)
my_scanner.should_receive(:attempt_login).once.with(pub_blank).and_return failure_blank
my_scanner.should_receive(:attempt_login).once.with(pub_pub).and_return success
my_scanner.should_receive(:attempt_login).once.with(pub_pri).and_return failure
@ -301,6 +303,7 @@ shared_examples_for 'Metasploit::Framework::LoginScanner::Base' do
it 'adds the success results to the successes attribute' do
my_scanner = login_scanner
my_scanner.should_receive(:valid!)
my_scanner.should_receive(:attempt_login).once.with(pub_blank).and_return failure_blank
my_scanner.should_receive(:attempt_login).once.with(pub_pub).and_return success
my_scanner.should_receive(:attempt_login).once.with(pub_pri).and_return failure
@ -319,6 +322,7 @@ shared_examples_for 'Metasploit::Framework::LoginScanner::Base' do
it 'stops after the first successful login' do
my_scanner = login_scanner
my_scanner.should_receive(:valid!)
my_scanner.should_receive(:attempt_login).once.with(pub_blank).and_return failure_blank
my_scanner.should_receive(:attempt_login).once.with(pub_pub).and_return success
my_scanner.should_not_receive(:attempt_login).with(pub_pri)

View File

@ -8,51 +8,51 @@ shared_examples_for 'Metasploit::Framework::LoginScanner::RexSocket' do
context 'send_delay' do
it 'is not valid for a non-number' do
ftp_scanner.send_delay = "a"
expect(ftp_scanner).to_not be_valid
expect(ftp_scanner.errors[:send_delay]).to include "is not a number"
login_scanner.send_delay = "a"
expect(login_scanner).to_not be_valid
expect(login_scanner.errors[:send_delay]).to include "is not a number"
end
it 'is not valid for a floating point' do
ftp_scanner.send_delay = 5.76
expect(ftp_scanner).to_not be_valid
expect(ftp_scanner.errors[:send_delay]).to include "must be an integer"
login_scanner.send_delay = 5.76
expect(login_scanner).to_not be_valid
expect(login_scanner.errors[:send_delay]).to include "must be an integer"
end
it 'is not valid for a negative number' do
ftp_scanner.send_delay = -8
expect(ftp_scanner).to_not be_valid
expect(ftp_scanner.errors[:send_delay]).to include "must be greater than or equal to 0"
login_scanner.send_delay = -8
expect(login_scanner).to_not be_valid
expect(login_scanner.errors[:send_delay]).to include "must be greater than or equal to 0"
end
it 'is valid for a legitimate number' do
ftp_scanner.send_delay = rand(1000) + 1
expect(ftp_scanner.errors[:send_delay]).to be_empty
login_scanner.send_delay = rand(1000) + 1
expect(login_scanner.errors[:send_delay]).to be_empty
end
end
context 'max_send_size' do
it 'is not valid for a non-number' do
ftp_scanner.max_send_size = "a"
expect(ftp_scanner).to_not be_valid
expect(ftp_scanner.errors[:max_send_size]).to include "is not a number"
login_scanner.max_send_size = "a"
expect(login_scanner).to_not be_valid
expect(login_scanner.errors[:max_send_size]).to include "is not a number"
end
it 'is not valid for a floating point' do
ftp_scanner.max_send_size = 5.76
expect(ftp_scanner).to_not be_valid
expect(ftp_scanner.errors[:max_send_size]).to include "must be an integer"
login_scanner.max_send_size = 5.76
expect(login_scanner).to_not be_valid
expect(login_scanner.errors[:max_send_size]).to include "must be an integer"
end
it 'is not valid for a negative number' do
ftp_scanner.max_send_size = -8
expect(ftp_scanner).to_not be_valid
expect(ftp_scanner.errors[:max_send_size]).to include "must be greater than or equal to 0"
login_scanner.max_send_size = -8
expect(login_scanner).to_not be_valid
expect(login_scanner.errors[:max_send_size]).to include "must be greater than or equal to 0"
end
it 'is valid for a legitimate number' do
ftp_scanner.max_send_size = rand(1000) + 1
expect(ftp_scanner.errors[:max_send_size]).to be_empty
login_scanner.max_send_size = rand(1000) + 1
expect(login_scanner.errors[:max_send_size]).to be_empty
end
end