Using fail2ban to Block Brute Force Attacks

From the category of log based tools I have chosen to present fail2ban because I consider it to be the best available log based brute force blocker. Basically, as any other log based brute force blockers, fail2ban will monitor the system log files and when certain configured events occur they will trigger fail2ban to block the offending host.

Here are the main features of fail2ban:

  • running as daemon (no delay to take actions as in cron based tools).
  • can use various methods to block the attack:
    • iptables (this is the default, and will most certainly be the best choice for most users)
    • TCP Wrappers (/etc/hosts.deny): this might be particular useful if you are running a VPS that has no access to iptables rules.
    • any other method you might need to implement in your firewall setup (you will have to define the rules yourself in this case).
  • can handle more than one service: sshd (default), apache, vsftpd/proftpd, etc.
  • can send e-mail notifications.
  • can ban IPs for a limited amount of time and since 0.6.1 can also permanently ban hosts.

The installation is not at all complicated as the author provides packages for major linux distributions. I will show how we can install fail2ban on Debian. By the way the Debian package is different than the source package you can find at the project page. This is because the author is closely collaborating with Debian maintainers to conform its software to the Debian rules and have it in the official Debian sources. This is very nice!

If we want to install fail2ban on a Debian system all we have to do is:

apt-get install fail2ban

this will take care of the dependencies you might not have on the system (python, iptables, lsb-base).

Once installed, it will be started automatically. The configuration file is located in /etc/fail2ban.conf. It will enable by default the protection against SSH brute force attacks. The configuration file contains each available parameter excellently commented and that should be the only documentation you will need for fail2ban.

Compared with other software, I found the need to change very few parameters from the default. Here are some of the important parameters from the main section: [DEFAULT] maxfailures= number of failures before IP gets banned. Defaults to 5. I like to lower this to 3: maxfailures = 3 bantime= number of seconds an IP will be banned. If set to a negative value, IP will never be unbanned (permanent banning). Defaults to 600 (10 min). bantime = -1 ignoreip= space separated list of IP’s to be ignored by fail2ban. No default. I like to add my own static management ips here just in case… ignoreip = 192.168.0.1

All fail2ban actions are logged and can be reviewed. The log file is defined using:

logtargets = /var/log/fail2ban.log

The SSH section works perfectly out of the box being aware of Debian log files names, etc:

[SSH]
enabled = true
logfile = /var/log/auth.log
port = ssh
timeregex = S{3}s{1,2}d{1,2} d{2}:d{2}:d{2}
timepattern = %%b %%d %%H:%%M:%%S
failregex = : (?:(?:Authentication failure|Failed [-/w+]+) for(?: [iI](?:llegal|nvalid) user)?|[Ii](?:llegal|nvalid) user|ROOT LOGIN REFUSED) .*(?: from|FROM) (?:::f{4,6}:)?(?PS*)

Here we can see the log file fail2ban will monitor for SSH attacks (/var/log/auth.log), the port that will be used to block the hosts (they will still be able to communicate with other protocols with our host even after ssh blocking) and also the regular expressions that will trigger fail2ban.

Besides the SSH section that is enabled by default the configuration file contains other usable sections for other programs (you just have to enable them as they default to disabled): SASL, Apache, ApacheAttacks, VSFTPD, PROFTPD. This can also be the starting point for writing your own rules targeted for any program you might need.

Here are the iptables definitions that will actually block the offending hosts:

fwchain = INPUT
fwstart = iptables -N fail2ban-%(__name__)s
iptables -A fail2ban-%(__name__)s -j RETURN
iptables -I %(fwchain)s -p %(protocol)s --dport %(port)s -j fail2ban-%(__name__)s
fwend = iptables -D %(fwchain)s -p %(protocol)s --dport %(port)s -j fail2ban-%(__name__)s
iptables -F fail2ban-%(__name__)s
iptables -X fail2ban-%(__name__)s
fwcheck = iptables -L %(fwchain)s | grep -q fail2ban-%(__name__)s
fwban = iptables -I fail2ban-%(__name__)s 1 -s  -j DROP
fwunban = iptables -D fail2ban-%(__name__)s -s  -j DROP

fwstart will create when starting the program for each of the defined active sections a different iptables chain. This will be called fail2ban-(name_of_section), for ex: fail2ban-SSH, fail2ban-VSFTPD, etc.

iptables -L -n
Chain INPUT (policy ACCEPT)
fail2ban-SSH  tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:22
Chain fail2ban-SSH (1 references)
RETURN     all  --  0.0.0.0/0            0.0.0.0/0

On program exit these chains are deleted. There is no persistence in fail2ban. If for any reason the program is restarted it will rescan the log files for failed attempts (only events newer then findtime- def 600) and it will add them to the active list. This is not at all a big limitation and I would not care about this… but just that you are aware that if you restart the program you will start fresh. The action that is taken when a host is banned will just add a new iptables rule in the program chain that will drop the traffic for the attacker.

Let me exemplify this: we are being attacked by a host with the IP 192.168.0.200 (just a private ip for the sake of the example) In system logs we see the following (/var/log/auth.log):

sshd[6787]: Did not receive identification string from 192.168.0.200
sshd[13299]: Invalid user lpd from 192.168.0.200
sshd[13299]: (pam_unix) authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=192.168.0.200
sshd[13299]: Failed password for invalid user lpd from 192.168.0.200 port 41458 ssh2
sshd[13324]: Invalid user lpa from 192.168.0.200
sshd[13324]: (pam_unix) authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=192.168.0.200
sshd[13324]: Failed password for invalid user lpa from 192.168.0.200 port 41689 ssh2

At this time fail2ban has seen enough authentication errors (with maxfailures = 3) and in fail2ban log file we will see:

/var/log/fail2ban.log
2006-07-01 16:06:39,261 INFO: SSH: 192.168.0.200 has 3 login failure(s). Banned.
2006-07-01 16:06:39,287 WARNING: SSH: Ban (permanent) 192.168.0.200

We have started with empty iptables rules that look like:

iptables -L -n
Chain INPUT (policy ACCEPT)
fail2ban-SSH  tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:22
Chain fail2ban-SSH (1 references)
RETURN     all  --  0.0.0.0/0            0.0.0.0/0

Meaning that all the SSH traffic will just pass thru the fail2ban-SSH chain without any change.

Once fail2ban has blocked our attacker 192.168.0.200 it will add a new iptables rule that will drop SSH traffic from this host. After this the rules will look like:

iptables -L -n
Chain INPUT (policy ACCEPT)
fail2ban-SSH  tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:22
Chain fail2ban-SSH (1 references)
** DROP       all  --  192.168.0.200        0.0.0.0/0**
RETURN     all  --  0.0.0.0/0            0.0.0.0/0

Using iptables to block the offending hosts is probably the best way to do this (and can be easily integrated in any existing iptables firewall), but as I said there are other methods available that might be useful in some cases (hosts.deny might be the only choice for VPS owners that don’t have access to iptables). You can look into the examples that come with fail2ban for how to easily implement this.

References:
http://www.fail2ban.org/wiki/index.php/Manual

Return to the main page: How to Block Brute Force Attacks

comments powered by Disqus