refactoring conditional logic

the class works but the conditional logic needs
refactoring to be smoothed out more.
bug/bundler_fix
David Maloney 2014-05-12 11:10:36 -05:00
parent 4e76330643
commit f84d763382
No known key found for this signature in database
GPG Key ID: DEDBA9DC3A913DB2
2 changed files with 139 additions and 1 deletions

View File

@ -1,4 +1,5 @@
require 'metasploit/framework/tcp/client'
require 'rex/proto/rfb'
require 'metasploit/framework/login_scanner/base'
require 'metasploit/framework/login_scanner/rex_socket'
@ -13,7 +14,84 @@ module Metasploit
include Metasploit::Framework::LoginScanner::RexSocket
include Metasploit::Framework::Tcp::Client
# 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
def attempt_login(credential)
result_options = {
credential: credential
}
begin
# Make our initial socket to the target
disconnect if self.sock
connect
# Create our VNC client overtop of the socket
vnc = Rex::Proto::RFB::Client.new(sock, :allow_none => false)
if vnc.handshake
if vnc_auth(vnc,credential.private)
result_options[:status] = :success
else
result_options.merge!({
status: :failed,
proof: vnc.error
})
end
else
result_options.merge!({
status: :connection_error,
proof: vnc.error
})
end
rescue ::EOFError, Rex::AddressInUse, Rex::ConnectionError, Rex::ConnectionTimeout, ::Timeout::Error => e
result_options.merge!({
status: :connection_error,
proof: e.message
})
end
::Metasploit::Framework::LoginScanner::Result.new(result_options)
end
private
# This method checks the VNC error to see if we should wait and retry
# @param error [String] The VNC error message received
# @return [Boolean] whether or not we should attempt the retry
def retry?(error)
return true if error =~ /connection has been rejected/ # UltraVNC
return true if error =~ /Too many security failures/ # vnc4server
false
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
# This method attempts the actual VNC authentication. It has built in retries to handle
# delays built into the VNC RFB authentication.
# @param client [Rex::Proto::RFB::Client] The VNC client object to authenticate through
# @param password [String] the password to attempt the authentication with
def vnc_auth(client,password)
success = false
5.times do |n|
if client.authenticate(password)
success = true
break
end
break unless retry?(client.error)
# Wait for an increasing ammount of time before retrying
delay = (2**(n+1)) + 1
select(nil, nil, nil, delay)
end
success
end
end
end

View File

@ -2,10 +2,70 @@ require 'spec_helper'
require 'metasploit/framework/login_scanner/vnc'
describe Metasploit::Framework::LoginScanner::VNC do
let(:private) { 'password' }
let(:blank) { '' }
let(:test_cred) {
Metasploit::Framework::LoginScanner::Credential.new( paired: false, private: private )
}
let(:blank_cred) {
Metasploit::Framework::LoginScanner::Credential.new( paired: false, private: blank )
}
subject(:login_scanner) { described_class.new }
it_behaves_like 'Metasploit::Framework::LoginScanner::Base'
it_behaves_like 'Metasploit::Framework::LoginScanner::RexSocket'
context '#attempt_login' do
it 'creates a new RFB client' do
Rex::Proto::RFB::Client.should_receive(:new).and_call_original
login_scanner.attempt_login(test_cred)
end
context 'when the socket errors' do
it 'returns a connection_error result for an EOFError' do
my_scanner = login_scanner
my_scanner.should_receive(:connect).and_raise ::EOFError
result = my_scanner.attempt_login(test_cred)
expect(result.status).to eq :connection_error
expect(result.proof).to eq ::EOFError.new.to_s
end
it 'returns a connection_error result for an Rex::AddressInUse' do
my_scanner = login_scanner
my_scanner.should_receive(:connect).and_raise ::Rex::AddressInUse
result = my_scanner.attempt_login(test_cred)
expect(result.status).to eq :connection_error
expect(result.proof).to eq ::Rex::AddressInUse.new.to_s
end
it 'returns a connection_error result for an Rex::ConnectionError' do
my_scanner = login_scanner
my_scanner.should_receive(:connect).and_raise ::Rex::ConnectionError
result = my_scanner.attempt_login(test_cred)
expect(result.status).to eq :connection_error
expect(result.proof).to eq ::Rex::ConnectionError.new.to_s
end
it 'returns a connection_error result for an Rex::ConnectionTimeout' do
my_scanner = login_scanner
my_scanner.should_receive(:connect).and_raise ::Rex::ConnectionTimeout
result = my_scanner.attempt_login(test_cred)
expect(result.status).to eq :connection_error
expect(result.proof).to eq ::Rex::ConnectionTimeout.new.to_s
end
it 'returns a connection_error result for an ::Timeout::Error' do
my_scanner = login_scanner
my_scanner.should_receive(:connect).and_raise ::Timeout::Error
result = my_scanner.attempt_login(test_cred)
expect(result.status).to eq :connection_error
expect(result.proof).to eq ::Timeout::Error.new.to_s
end
end
end
end