I’ve been a big fan of Fail2Ban for a decade or longer. It’s a quick way to introduce some brute force protection to your system and it generally just works “out of the box”.
Recently, however, I found a situation where it didn’t really work nicely so I found myself knee-deep in Fail2Ban documentation. I was installing the awesome Citadel Groupware and its logs are not very standard. For some reason, Fail2Ban basically has date formats that it understands hard coded into it. It’s pretty flexible but if you have an app that prints time stamps in a format that Fail2Ban doesn’t understand, it looks like you’re out of luck.
It may be possible to bend Fail2Ban to my will but honesty, it takes like 5 minutes to write a script for my one particular use-case. So, in this case, it’s simply easier to make a script to do do the dirty work.
I have the luxury of installing this as a private system so I’ve already locked down the web ports to just my IP, but I can’t do that the email ports. Every mail server needs to connect to those, so I can’t firewall them off. But, I can look for brute force attempts and issue a Uncomplicated Firewall (UFW) command to block those IPs.
The script I started with is below. I run it every few minutes. Given the fact that I never type my own credentials in when I check mail, there’s pretty much a zero chance that I will get locked out. But, if you are concerned about that, you can easily modify the grep to exclude your own IP. It also wouldn’t not be too hard to write the banned IPs to a file, and every 20 minutes or so, unblock them with another script. Lots of ways to deal with that problem if it exists.
Another modification may be to build a list of the IPs before sending the email so you only get one email for each blocking run instead of a single email for each. I will enhance this as I go along, but it was important to get some level of brute force protection in place as soon as possible.
#!/bin/bash # # Making a fail2ban for SMTP because the the real fail2ban doesn't like Citadel's time stamp # Set some stuff EMAIL= <set your email address> HOST=`hostame` for ip in `/bin/grep "bad password" /var/log/syslog | /bin/grep -o "[0-9.:A-z]*>$" | /bin/sed s'/>//' | sort -u `;do # Check if it is already blocked banned=`/usr/sbin/ufw status | /bin/grep $ip` if [ $? -ne 0 ] then # Block it /usr/bin/sudo /usr/sbin/ufw deny from $ip comment 'Fail2ban_citadel autoblock' /usr/local/citadel/citmail -i -- $EMAIL<<END_OF_EMAIL Subject: Blocked IP $ip on $HOST To: $EMAIL Blocked $ip for brute force END_OF_EMAIL fi done