Brute force stats

Out of curiosity and for my own entertainment, I retrieved a few numbers of the logs of one Debian based server which is not behind any firewall and which is open for SSH connections on port 22.

Nov 15: ( 122 hits)    1 +  30 failed (= 31),     4 uniq,   4 refused,   4 uniq;   3 new denied
Nov 16: ( 584 hits)   15 + 254 failed (= 269),   28 uniq,   6 refused,  30 uniq;   6 new denied
Nov 17: ( 330 hits)   10 + 167 failed (= 177),   24 uniq,  19 refused,  24 uniq;   6 new denied
Nov 18: ( 140 hits)    1 +  48 failed (= 49),     7 uniq,   3 refused,   7 uniq;   5 new denied
Nov 19: (1275 hits)  349 + 205 failed (= 554),  314 uniq,  30 refused, 331 uniq;  10 new denied
Nov 20: (4214 hits) 1434 +  57 failed (= 1491), 550 uniq, 230 refused, 602 uniq;  80 new denied
Nov 21: (4102 hits)  783 + 407 failed (= 1190), 573 uniq, 706 refused, 709 uniq; 162 new denied
Nov 22: (2221 hits)  230 + 256 failed (= 486),  266 uniq, 719 refused, 465 uniq;  85 new denied
Nov 23: (2131 hits)  115 + 331 failed (= 446),  153 uniq, 973 refused, 396 uniq;  58 new denied

As is rather obvious, a distributed brute force attack started around November 19 and is still ongoing. It did calm down a bit but a number of nearly 1000 actually refused connections is rather high. (Connections are refused based on the fact that the IP address is known to be part of the attack, i.e. failed login attempts were previously recorded.)

The uniq numbers try to give an impression of how many single hosts were involved since a single host generally will connect several times. These numbers are not completely accurate but they come close.

The number of all uniq IP addresses involved from November 19 to 23 is 837. BTW, 40 of these addresses were already recorded one year ago.

"Code"

For reference, here is the main part of the code I used. Comes with no warranty. Warning: It's quick and dirty, and might leave your pets comatose and incontinent at least for the duration of the attack.

AUTHLOG=~/auth.log.complete
DENYLOG=~/denyhosts.complete
MONTH="Nov" ; for DAY in 15 16 17 18 19 20 21 22 23 ; do 
  DATE=$(date -d"$MONTH $DAY" +'%b %e')
  ISODATE=$(date -d"$MONTH $DAY" +%Y-%m-%d)
  LOGTOTAL=$(egrep -c "^$DATE .* sshd.*: " $AUTHLOG)
  AUTHFAIL=$(egrep -c "^$DATE .* sshd.*: \(pam_unix\) authentication failure; logname=.* rhost=" $AUTHLOG)
  USERINV=$(egrep -c "^$DATE .* sshd.*: Invalid user .* from " $AUTHLOG)
  REFUSED=$(egrep -c "^$DATE .* sshd.*: refused connect from " $AUTHLOG)
  UNIQHOSTS=$(sed -ne "
    s/^$DATE .* sshd.*: (pam_unix) authentication failure; logname=.* rhost=\([^ ]*\).*$/\1/p
    s/^$DATE .* sshd.*: Invalid user .* from \([^ ]*\)$/\1/p
    " $AUTHLOG | sort -u | wc -l)
  UNIQALL=$(sed -ne "
    s/^$DATE .* sshd.*: (pam_unix) authentication failure; logname=.* rhost=\([^ ]*\).*$/\1/p
    s/^$DATE .* sshd.*: Invalid user .* from \([^ ]*\)$/\1/p
    s/^$DATE .* sshd.*: refused connect from .* (::ffff:\([^ ]*\))$/\1/p
    " $AUTHLOG | sort -u | wc -l)
  NEWDENIED2=$(grep -c "$ISODATE .*new denied hosts: .*," $DENYLOG )
  NEWDENIED1=$(grep -c "$ISODATE .*new denied hosts:"     $DENYLOG )
 
  echo "$DATE: ($LOGTOTAL total) $AUTHFAIL + $USERINV failed (= $((AUTHFAIL+USERINV))),\
 $UNIQHOSTS uniq, + $REFUSED refused, $UNIQALL uniq; $((NEWDENIED2+NEWDENIED1)) new denied"
done