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 ;)).
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
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
sudo vim jail.local
Enter the following informaton into this file to override defaults set in the
[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.
[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
Create a new file called
wordpress.conf in the
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
[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
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
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/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:
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)  <HOST>.*POST.*(wp-login\.php|xmlrpc\.php).* 200 `- Ignoreregex: 0 total Date template hits: |- [# of hits] date format |  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.