Fail2ban is a program that monitors logging files where programs log failed login
attempts.
If failed logins accumulate that can be assigned to one IP address, this IP address gets blocked for a while by a firewall rule. Specifically, Fail2ban detects when a hacker tries to guess a password by (automated) trial and error, such as with a program like hydra. In this case, IP traffic from this host is blocked for 10 minutes by default.
Fail2ban can be installed easily on most distributions. The supplied configuration files provide settings for many common protocols or programs, including SSH, FTP, SMTP, POP, and IMAP. However, most of these services aren’t active by default. Fail2ban thus doesn’t protect against systematic login attempts until the configuration is adjusted and the programs to be monitored are explicitly activated.
Fail2ban can also be adapted to your own web applications with a little effort. To do this, the application must log incorrect login attempts in a text file. The Fail2ban configuration must be supplemented so that the program evaluates this file.
Fail2ban doesn’t detect when coordinated login attempts are made from different hosts. This is the case when the attacker has an entire botnet—that is, an entire network of computers that they can control remotely. The same problem exists if the attack comes from an IPv6 network. With IPv6, it’s relatively easy for the attacker to perform each login attempt using a different IPv6 address.
On Debian and Ubuntu, you can simply install Fail2ban via apt install fail2ban. On Ubuntu, the package is located in the universe package source, which is active by default but officially not supported.
On RHEL and the like, the package isn’t available in the official package sources. For this reason, you must first enable the Extra Packages for Enterprise Linux (EPEL) external package source. For most RHEL clones, this can be easily done using dnf install epelrelease. For RHEL, you should follow the instructions on the EPEL website at https://fedoraproject.org/wiki/EPEL. Then install Fail2ban via dnf install fail2ban.
On Debian and Ubuntu, Fail2ban starts automatically after the installation. On RHEL, you must provide some help at this point as well:
systemctl enable --now fail2ban
Even then, Fail2ban still isn’t active on RHEL. This only changes when you change the configuration and enable the services to be monitored (enabled = true). Debian and Ubuntu have basically the same restriction, but at least SSH is monitored there by default.
Don’t forget to inform Fail2ban after changing configuration files. To do this, you must run systemctl reload fail2ban.
The numerous configuration files of Fail2ban are located in the /etc/fail2ban directory. The configuration concept is that various *.conf files already contain comprehensive default settings. Note, however, that these files will be overwritten when the package is updated. You therefore shouldn’t touch the *.conf files at all and should instead make all your own settings in *.local files of the same name.
The structure of the default configuration is extremely complex. Prior to making any changes, you need to become familiar with the terminology of Fail2ban, at least in a basic way:
Fail2ban is implemented as a client-server application. The server is started by systemd. Among other things, the client is used to query the current status, to reread the configuration, and to execute actions manually.
Significant Differences Depending on the Distribution: Note that the default configurations on Debian/Ubuntu and on RHEL differ significantly. This is not least due to different logging strategies and files in these two distribution families.
To give you an idea of what the Fail2ban configuration looks like, we have printed the parts of the configuration that affect the SSH server ahead. The listings that follow, with excerpts from several configuration files—shortened for space reasons—refer to the default configuration of Ubuntu 22.04:
# Basic settings
# File /etc/fail2ban/jail.conf
[DEFAULT]
maxretry = 5
findtime = 10m
bantime = 10m
banaction = iptables-multiport
...
# Filter for SSH
# File /etc/fail2ban/filter.d/sshd.conf
_daemon = sshd
cmnfailre =
^[aA]uthentication (?:failure|error|failed) for <F-USER>....
^User not known to the underlying authentication module ...
^Failed \S+ for invalid user <F-USER>(?P<cond_user>\S+)...
...
failregex = %(cmnfailre)s
...
# Jail for SSH
# File /etc/fail2ban/jail.conf
[sshd]
port = ssh
logpath = %(sshd_log)s
# Debian/Ubuntu-specific default settings
# File /etc/fail2ban/jail.d/defaults-debian.conf
[sshd]
enabled = true
Finally, here’s an explanation of some important parameters of the default settings:
Fail2ban is most commonly used to secure the SSH server. On Debian and Ubuntu, Fail2ban is preconfigured to automatically block repeated login attempts (due to defaults-debian.conf, discussed earlier).
On RHEL, you must enable the jail for sshd yourself. To do this, you need to create a new jail.local file with the following content:
# File /etc/fail2ban/jail.local (RHEL & clones)
[sshd]
enabled = true
The systemctl reload fail2ban command activates the new rules.
SSH Protection via Firewall: An alternative way to protect the SSH server from login attempts or DDoS attacks is to use appropriate firewall rules.
The /etc/fail2ban/jail.conf file contains countless ready-made jails for the most common distributions. Their activation should therefore be quite simple: as in the previous SSH example, you must enter the jail name in square brackets in jail.local and add the enabled = true line below it. That’s all!
Unfortunately, there’s a catch to this because many entries in jail.conf are old and don’t match the current configuration of the corresponding services. The locations of log files have changed, and possibly also their formats, so that the filter rules are no longer correct. In our tests, this kind of problem occurred significantly more often on Ubuntu than on RHEL.
If systemctl reload fail2ban results in an error after a configuration change, the first thing you should do is use systemctl status fail2ban to investigate the error message. Often it’s sufficient to specify the correct location of the logging file in jail.local (logpath = /var/log/<name>). Sometimes, however, you have to take the trouble to adapt further details of the configuration to the current conditions yourself. Up-to-date notices can usually be found on the internet.
Even if a jail seems to work without any obvious error messages, it’s a good idea to verify its operation via a few intentionally incorrect logins.
Using fail2ban-regex, you can try regular expressions; you can use this command in two ways:
fail2ban-regex "line" "regex"
fail2ban-regex <loggingfile> /etc/fail2ban/filter.d/<filterfile>
The following example demonstrates the test of a custom filter file for MySQL. The output is heavily abridged due to space limitations:
fail2ban-regex /var/log/mysql/error.log \
/etc/fail2ban/filter.d/mysqld-auth.local
Running tests:
Use failregex filter file : mysqld-auth, basedir: /etc/fail2ban
Use log file : /var/log/mysql/error.log
Use encoding : UTF-8
Results:
Failregex: 1 total
#) [# of hits] regular expression
2) [1] ... Access denied for user '[^']+'@'<HOST>'
WordPress: Instructions on how to secure login attempts on the popular WordPress content management system (CMS) with Fail2ban can be found at http://s-prs.co/v5696108.
If you have a self-developed web application running on a server, you can of course also secure its login using Fail2ban. The basic idea is that you do this by looking for login errors in the log of your web server. The following example assumes that the Apache web server is in use and that a message in the form myown login failed is logged when a login fails (of course, you must replace myown with your own name in the following two listings):
# File /etc/fail2ban/filter.d/myown.conf
[INCLUDES]
before = apache-common.conf
[Definition]
failregex =
^%(_apache_error_client)s (myown login failed)$
^%(_apache_error_client)s (myown login failed), referer: .*$
ignoreregex =
# File /etc/fail2ban/jail.d/myown.conf
[myown]
enabled = true
port = http,https
logpath = %(apache_error_log)s
maxretry = 10
fail2ban-client status returns a list of all active jails:
fail2ban-client status
Status
Number of jail: 4
Jail list: dovecot, myown, postfix, sshd
If you add the name of a jail to this command, you’ll get corresponding detailed information. Currently banned indicates which IP addresses are currently blocked, and Total banned indicates how often IP addresses have been blocked in the past:
fail2ban-client status sshd
Status for the jail: sshd
filter
File list: /var/log/auth.log
Currently failed: 0 Total failed: 242526 action Currently b
anned: 1 IP list: 118.182.nnn.nnn Total banned: 32606
You can use set <jailname> unbanip to unblock an IP address that was incorrectly blocked:
fail2ban-client set sshd unbanip 1.2.3.4
fail2ban-client is also an important debugging tool. fail2ban-client -d outputs the entire configuration that’s currently valid, taking into account only those filters, jails, and actions that are actually in use (due to enabled = yes and due to the setting of banaction).
Editor’s note: This post has been adapted from a section of the book Hacking and Security: The Comprehensive Guide to Penetration Testing and Cybersecurity by Michael Kofler, Klaus Gebeshuber, Peter Kloep, Frank Neugebauer, André Zingsheim, Thomas Hackner, Markus Widl, Roland Aigner, Stefan Kania, Tobias Scheible, and Matthias Wübbeling. These authors are a team of security specialists who have decades of experience working as penetration testers, administrators, and developers. Their unique expertise has taught them how hackers operate and they use this insight to teach others how to effectively defend systems against attacks.