metasploit-framework/modules/auxiliary/scanner/finger/finger_users.rb

204 lines
4.9 KiB
Ruby

##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::Tcp
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
def initialize
super(
'Name' => 'Finger Service User Enumerator',
'Description' => 'Identify valid users through the finger service using a variety of tricks',
'Author' => 'hdm',
'License' => MSF_LICENSE
)
register_options([
Opt::RPORT(79),
OptString.new('USERS_FILE',
[ true, 'The file that contains a list of default UNIX accounts.',
File.join(Msf::Config.install_root, 'data', 'wordlists', 'unix_users.txt')
]
)], self.class)
end
def run_host(ip)
@users = {}
begin
vprint_status "#{rhost}:#{rport} - Sending empty finger request."
finger_empty
vprint_status "#{rhost}:#{rport} - Sending test finger requests."
finger_zero
finger_dot
finger_chars
vprint_status "#{rhost}:#{rport} - Sending finger request for user list: #{finger_user_common.join(", ")}"
finger_list
rescue ::Rex::ConnectionError
rescue ::Exception => e
print_error("#{e} #{e.backtrace}")
end
report_service(:host => rhost, :port => rport, :name => "finger")
if(@users.empty?)
print_status("#{ip}:#{rport} No users found.")
else
print_good("#{ip}:#{rport} Users found: #{@users.keys.sort.join(", ")}")
report_note(
:host => rhost,
:port => rport,
:type => 'finger.users',
:data => {:users => @users.keys}
)
end
end
def finger_empty
connect
sock.put("\r\n")
buff = finger_slurp_data
parse_users(buff)
disconnect
end
def finger_zero
connect
sock.put("0\r\n")
buff = finger_slurp_data
parse_users(buff)
disconnect
end
def finger_dot
connect
sock.put(".\r\n")
buff = finger_slurp_data
parse_users(buff)
disconnect
end
def finger_chars
connect
sock.put("m m m m m m m m\r\n")
buff = finger_slurp_data
if buff.scan(/\r?\nm\s/).size > 7
@multiple_requests = true
vprint_status "#{rhost}:#{rport} - Multiple users per request is okay."
end
parse_users(buff)
disconnect
end
def finger_list
if !@multiple_requests
finger_user_common.each do |user|
next if @users[user]
connect
vprint_status "#{rhost}:#{rport} - Sending finger request for #{user}..."
sock.put("#{user}\r\n")
buff = finger_slurp_data
ret = parse_users(buff)
disconnect
break if not ret
end
else
while !finger_user_common.empty?
user_batch = []
while user_batch.size < 8 and !finger_user_common.empty?
new_user = finger_user_common.shift
next if @users.keys.include? new_user
user_batch << new_user
end
connect
vprint_status "#{rhost}:#{rport} - Sending finger request for #{user_batch.join(", ")}..."
sock.put("#{user_batch.join(" ")}\r\n")
buff = finger_slurp_data
ret = parse_users(buff)
disconnect
break if not ret
end
end
end
def finger_slurp_data
buff = ""
begin
while(res = sock.get_once(-1, 5) || '')
buff << res
break if buff.length > (1024*1024)
end
rescue ::Interrupt
raise $!
rescue ::Exception
end
buff
end
def finger_user_common
if(! @common)
File.open(datastore['USERS_FILE'], "rb") do |fd|
data = fd.read(fd.stat.size)
@common = data.split(/\n/).compact.uniq
@common.delete("")
end
end
@common
end
def parse_users(buff)
buff.each_line do |line|
uid = nil
next if line.strip.empty?
# Ignore Cisco systems
return if line =~ /Line.*User.*Host.*Location/
next if line =~ /user not found/i
next if line =~ /no such user/i
next if line =~ /must provide username/
next if line =~ /real life: \?\?\?/
next if line =~ /No one logged on/
next if line =~ /^Login\s+Name\s+TTY/
# print_status(">> #{line}")
# No such file or directory == valid user bad utmp
# Solaris
if(line =~ /^([a-z0-9\.\_]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)/)
uid = $1
if ($2 != "Name")
@users[uid] ||= {}
end
end
# IRIX
if(line =~ /^\s*Login name:\s*([^\s]+)\s+/i)
uid = $1
@users[uid] ||= {} if uid
end
# Debian GNU/Linux
if(line =~ /^\s*Username:\s*([^\s]+)\s+/i)
uid = $1
@users[uid] ||= {} if uid
end
if uid
print_good "#{rhost}:#{rport} - Found user: #{uid}" unless @users[uid] == :reported
@users[uid] = :reported
next
end
end
return true
end
end