You already know that it is not so smart to leave SSH running on your servers on default port and accessible from every internet address (ie. no firewall restrictions, no host allow/deny).. but in real world it happens to do so since, let’s say, you have no static IP, you have no access to firewall rules and so on.

In cases like this, I use to secure linux boxes with Swatch []. Swatch started out as the “simple watchdog” for actively monitoring log files produced by UNIX’s syslog facility. You can define rules and switches, that can start actions (launch a command, issue a new iptables rule..) when certain events are detected in the monitored log. So, to secure your box from bruteforce ssh attacks, you just have to tell Swatch to watch /var/log/secure on Red Hat based distros (/var/log/auth on Debian-Ubuntu flavours) for failed ssh login attempts.

Following instructions works on Centos/Fedora/RedHat. You will have to change them according to your linux OS. First of all we need to install the swatch package using the yum facility (this will also install all the relative dependencies):

sudo yum install swatch perl-Time-HiRes

NOTE: perl-Time-HiRes is needed but missing from the dependencies automatically resolved by yum Now that you have swatch, you need to create an /etc/swatch.conf file.

watchfor    /Failed password for/
exec "/opt/bad_user $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15"

This essentially tells Swatch to check for the magic word “Failed”, then launch the /opt/bad_user script (carrying out 15 fields of the log line). Here is my example /opt/bad_user recipe:

# filename: bad_user
# author: ops[at]agate[dot]pw
IP=`echo $* | sed 's/^.* from //' | awk '{print $1}' | sed 's/::ffff://'`
ATTEMPTS=`grep $IP /var/log/secure | grep "Failed password for"  | wc -l`

if [ $ATTEMPTS -gt 3 ]
       /sbin/iptables -I INPUT -s $IP -j DROP
       echo "/sbin/iptables -D INPUT -s $IP -j DROP >/dev/null 2>&1" | at now +$MINUTES minutes  >/dev/null 2>&1 > /tmp/.bad_user.$$
       (echo "Suspicious attempt from $IP blocked on $HOSTNAME" ; \
       echo ; echo $* ; echo "IP=$IP" ; echo "ATTEMPTS=$ATTEMPTS" ; \
       echo "Blocking for $MINUTES minutes" ; \

       cat /tmp/.bad_user.$$ ) | mail -s "Bad user blocked on $HOSTNAME" $MAILBOX

rm -f /tmp/.bad_user.$$

This script essentially tracks failed attempts from the “bad” IP address; if attemps are more than 3 (gt: greater than) than we blacklist it (the script creates an Iptables drop rule) for a given time (MINUTES: 5 minutes in the script example) than it will delete the drop rule - useful if you forget your password ;) Afterwards, the script informs us on the given admin e-mail address (MAILBOX). NOTE: you will probably need to install mailx in order to send e-mails Now we need to assure that Swatch will start at system boot. Let’s append the following string at /etc/rc.local:

/usr/bin/perl /usr/bin/swatch -c /etc/swatch.conf -t /var/log/secure --awk-field-syntax --tail-args -F &

Example mail report:

Date: Tue, 02 Oct 2012 14:11:04 +0200
From: root <root@frozen.localdomain>
Subject: Bad user blocked on frozen.localdomain
User-Agent: Heirloom mailx 12.4 7/29/08

Suspicious attempt from blocked on frozen.localdomain

Oct 2 13:43:17 frozen sshd[1759]: Failed password for invalid user badw0lf from port 48338
Blocking for 5 minutes