refactor telnet_login
parent
87a9ee9a69
commit
c074ebda7b
|
@ -178,8 +178,6 @@ module Metasploit
|
|||
raise NotImplementedError
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
attr_accessor :sock
|
||||
|
||||
end
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue