It resulted from an active dictionary attack on one of our 8.7.1 servers so this quick/dirty script to see what was happening.
Run the program without any arguments and as the zimbra user. You need read access to /opt/zimbra/log for whatever user to run the script as.
Output is by user and sorted by ip reference count and looks like this.
user_a@example.com
[ 4] - 189.170.193.209
[ 4] - 164.136.12.177
[ 4] - 144.136.12.187
[ 3] - 51.62.160.157
[ 1] - 118.253.220.248
[ 1] - 129.55.121.74
[ 1] - 47.115.1.60
[ 1] - 127.244.31.10
[ 4] - 174.136.12.187 failed imap
[ 4] - 188.170.193.209 failed imap
[ 4] - 174.136.12.177 failed imap
[ 3] - 50.62.160.157 failed imap
[ 1] - 117.253.220.248 failed imap
[ 1] - 119.55.121.74 failed imap
[ 1] - 117.244.31.10 failed imap
[ 1] - 37.115.1.60 failed imap
user_b@example.com
[ 9] - 137.142.50.234
[ 2] - 25.170.150.130
[ 1] - 137.142.50.234 failed web
So user_b@example.com mistyped their zimbra login information but was able to login 9 times correctly.
Code: Select all
#!/usr/bin/perl
use Data::Dumper qw(Dumper);
%ip_list = (); #ip list
%fip_list = (); #failed ip list
$audit_log = 0; #todays logging
chdir "/opt/zimbra/log";
for (glob 'audit.log*') {
# audit.log is always todays stuff
#print "Opening file $_";
if ($_ eq 'audit.log')
{
$audit_log = 1;
open (IN, sprintf("cat %s |", $_))
or die("Can't open pipe from command 'zcat $filename' : $!\n");
}
else
{
$audit_log = 0;
open (IN, sprintf("zcat %s |", $_))
or die("Can't open pipe from command 'zcat $filename' : $!\n");
}
while (<IN>)
{
if (m#invalid password#i)
{
#print $_;
if (m#ImapServer#i) {
my($ip,$user) = m#.*\s+\[ip=.*;oip=(.*);via=.*;\]\s*.* failed for\s+\[(.*)\].*$#i;
$uagent = "imap";
#print " - ip is $ip, user is $user, agent is $uagent\n";
#print $_;
++$ip_list{$user}{$ip}; #we loop by this for report
++$fip_list{$user}{$ip}{'count'};
++$fip_list{$user}{$ip}{'imap'};
}
elsif (m#Pop3Server#i)
{
my($ip,$user) = m#.*\s+\[ip=.*;oip=(.*);\]\s*.* failed for\s+\[(.*)\].*$#i;
$uagent = "pop";
#print " - ip is $ip, user is $user, agent is $uagent\n";
#print $_;
++$ip_list{$user}{$ip}; #we loop by this for report
++$fip_list{$user}{$ip}{'count'};
++$fip_list{$user}{$ip}{'pop'};
}
elsif (m#http#i)
{
my($user,$ip,$uagent) = m#.*\s+\[name=(.*);oip=(.*);ua=(.*);\].*$#i;
$uagent = "web";
#print " - ip is $ip, user is $user, agent is $uagent\n";
#print $_;
++$ip_list{$user}{$ip}; #we loop by this for report
++$fip_list{$user}{$ip}{'count'};
++$fip_list{$user}{$ip}{'web'};
}
}
elsif (m#AuthRequest#i && ($_ !~ m/zimbra/i))
{
my($user,$ip,$uagent) = m#.*\s+\[name=(.*);oip=(.*);ua=(.*);\].*$#i;
++$ip_list{$user}{$ip};
#$ip_list{$user}{'Agent'} = $uagent;
if ($audit_log == 1) { print $_; }
#print " - ip is $ip, user is $user, agent is $uagent\n";
}
}
close (IN);
}
#debug
#print Dumper \%ip_list;
#print Dumper \%fip_list;
for $user (sort {$ip_list{$b} <=> $ip_list{$a}} keys %ip_list )
{
print "\n",$user,"\n";
for $ip (sort {$ip_list{$user}{$b} <=> $ip_list{$user}{$a}} keys %{$ip_list{$user}} )
{
# See count of how many times
printf (" [%4d] - %s\n", $ip_list{$user}{$ip},$ip);
#printf ("%s\n",$ip);
}
# failed
for $ip (sort {$fip_list{$user}{$b} <=> $fip_list{$user}{$a}} keys %{$fip_list{$user}} )
{
# See count of how many times
printf (" [%4d] - %s ", $fip_list{$user}{$ip}{count},$ip);
printf " failed web " if exists $fip_list{$user}{$ip}{'web'};
printf " failed imap " if exists $fip_list{$user}{$ip}{'imap'};
printf " failed pop " if exists $fip_list{$user}{$ip}{'pop'};
printf ("\n");
#%%% we can have different user's in fip_list that ip_list doesn't have.
#printf ("%s\n",$ip);
}
}