Hello world! There are a number of tools that I find absolutely indispensable when working on system administration tasks. Some of these tools assist with securing/hardening web servers to prevent DDoS or other types of hacks. I’m going to be delving deeper into Fail2ban and how it can be setup and configured to help with just about any type of issue you and your server may be facing.
Firstly, I’m a huge proponent of Ubuntu and their server operating systems, as you’ve probably seen from my other blogs, so I’ll be assuming you’re operating on the same. Those of you operating on different versions of Linux, you’ll likely recognize when to use another command. To those of you operating on Windows servers, you have my condolences (just kidding ;)).
The Basics
This part of the process is simple enough. Update and upgrade your installation of Ubuntu, for sanity’s sake. Install Fail2ban.
sudo apt update && sudo apt upgrade -y
sudo apt install fail2ban
Configuring Fail2ban
We’ll be operating in the /etc/fail2ban/
folder for the most part. Though, later on, we’ll be referring to log files to give Fail2ban more information.
If you open the jail.conf
file, you’ll notice pretty early on that they recommend you not touch that file. It’ll be overwritten quite commonly, so you should enter all of your configurations in a new jail.local
file.
sudo vim jail.local
Enter the following informaton into this file to override defaults set in the jail.conf
file.
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 #your.ip.here
bantime = 3600
findtime = 600
maxretry = 5
[sshd]
enabled = true
This will set the default ban time to 3600 seconds (how long they’re locked out), the find time to 600 seconds (how long of a period to search for instances to ban), and maxretry to 5 (the number of times before triggering the rule. You may choose to increase or decrease these rules based on your own preferences. Be careful when using -1
bantime, as it is a permanent ban which can lock you out of your server. If you’re a responsible adult and are using ssh keys to log in, you should be fine. Always have a backup entryway in case of failures.
Setting [sshd] enabled = true
enables the basic sshd
rule to ban anyone failing to access ssh five times within 600 seconds. This will ban the offending individual for 3600 seconds. This is often more than enough time to prevent your server from being overloaded with false requests.
Creating Custom Rules
As you may have noticed from my other blogs, I’m often running open-source web applications on my servers. This means that I’m often open to common attacks and DDoS techniques used by script kiddies across the globe.
Looking through your web-server logs, you may notice many different types of attacks. You can create rules for these attacks using regular expressions in combination with Fail2ban rules.
I’ve previously written about XML-RPC attacks against WordPress and how to prevent them, but I’ll be outlining another option here using fail2ban, which may actually be a more elegant solution, though potentially not as secure.
Firstly, new rules should be placed in the /etc/fail2ban/filter.d/
folder, which you’ll notice has a number of already configured rules you may want to enable in your /etc/fail2ban/jail.local
file.
Create a new file called wordpress.conf
in the filter.d
folder:
vim /etc/fail2ban/filter.d/wordpress.conf
I run Apache2 as my web-server of choice, so my log files are located in /var/log/apache2/
and specifically the newest access logs would be in access.log
, though you can see an archive of older logs in the numbered files. Two specific lines that cause me grief are the following:
XX.XXX.XXX.XXX - - [13/Jun/2019:16:07:58 -0400] "POST /wp-login.php HTTP/1.1" 200 5382 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
XX.XXX.XXX.XXX - - [13/Jun/2019:16:07:58 -0400] "POST /xmlrpc.php HTTP/1.1" 200 3588 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
The first bit of the line item is the IP address (redacted), then we have a couple dashes and the date. Following, we have the type of request, the URI, the type, and the HTTP code type response. In the case 200 – OK. That’s all we really need to create our regular expressions, as this is all the common information we need. You’ll see numerous requests like this one coming in on a daily basis.
Add the following configuration to the newly created wordpress.conf
file:
[Definition]
failregex = <HOST>.*POST.*(wp-login\.php|xmlrpc\.php).* 200
As you can see, we specify where we would find the host in the regular expression. Then we specify that it is followed by any characters leading up to POST. Then we are looking for any characters leading up to wp-login.php
or xmlrpc.php
. Following that, any characters leading up to the 200 code.
This regex calls out two different attacks. Firstly, POST
calls to wp-login.php
with a 200 error are failures, as a successful login will return a redirect. Secondly, and similarly, POST
calls to xmlrpc.php are treated the same way.
Once we’ve saved this configuration file, we’ll need to enable it and set some configuration parameters in our jail.local
file. This is what our file should look like after the addition:
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 #your.ip.here
bantime = 3600
findtime = 600
maxretry = 5
[sshd]
enabled = true
[wordpress]
enabled = true
port = http,https
filter = wordpress
logpath = /var/log/apache2/access.log
maxretry = 5
bantime = 3600
As you can see, we specify that our requests may be coming over the http
or https
ports. They should be filtered based on the wordpress.conf
filter (excluding the .conf
). The rule should find and filter bad actors based on our log file which would be /var/log/apache2/access.log
or /var/log/nginx/access.log/
or something similar based on your own configurations.
Testing Your New Configuration
Fail2ban gives us a number of commands that we can use to test our setup.
You can check if your server is running with: sudo fail2ban-client status
You can reload your fail2ban configuration with: sudo fail2ban-client reload
You can even see all commands just by running: sudo fail2ban-client
However, we’re looking to see how effective our fail2ban configuration is at spotting issues in our existing logs. We’ll run fail2ban-regex
specifying our access.log
input file, and our filter.d/wordpress.conf
custom configuration.
sudo fail2ban-regex /var/log/apache2/access.log /etc/fail2ban/filter.d/wordpress.conf
For me, it takes a moment and then spits out the following:
Running tests
=============
Use failregex filter file : wordpress, basedir: /etc/fail2ban
Use log file : /var/log/apache2/access.log
Use encoding : UTF-8
Results
=======
Failregex: 4584 total
|- #) [# of hits] regular expression
| 1) [4584] <HOST>.*POST.*(wp-login\.php|xmlrpc\.php).* 200
`-
Ignoreregex: 0 total
Date template hits:
|- [# of hits] date format
| [13957] Day(?P<_sep>[-/])MON(?P=_sep)Year[ :]?24hour:Minute:Second(?:\.Microseconds)?(?: Zone offset)?
`-
Lines: 13957 lines, 0 ignored, 4584 matched, 9373 missed [processed in 4.45 sec]
Missed line(s): too many to print. Use --print-all-missed to print all 9373 lines
As you can see, we successfully run our configuration failregex
against the log retrieving 4584 offending lines. It then lets me know that using the “Date template hint” I could have found 13957 lines. Since this is a log file where every single line includes the date, you can see that it coincides with the number of lines at the bottom, and is effectively useless data. At the very bottom, we see that out of 13957 lines 0 were ignored and 4584 were matched. We don’t need to print or process the other lines, as they should have been legal access to our web-server.
At this point, we can look through additional lines in our access files for patterns in access, and see what we can limit through Fail2ban custom rules. You could even spend some time looking through the additional premade rules to see if any apply to you and enable them in your base configuration file – after all, script kiddies use some pretty common attack vectors.
Happy banning!