Fail2ban: Setup, Configure, Customize, Test

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.

ignoreip = ::1
bantime = 3600
findtime = 600
maxretry = 5
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:

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:

ignoreip = ::1
bantime = 3600
findtime = 600
maxretry = 5
enabled = true
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


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!

Oops! Password Reset Ubuntu: Windows Subsystem for Linux (WSL)

I typically like to write a blog whenever I encounter a problem that I have to research a solution. This particular issue was forgetting the password to my administrative account in my WSL Ubuntu installation. If you ever get into this same predicament, there are a couple really simple steps to get you back up and running.

Firstly, start by opening your WSL Ubuntu installation and figuring out what your user is. If you kept it the default ubuntu feel free to skip this part.

Next, you’ll want to log out (important) using exit.

Once you’re out, you can change the default user with which your computer is logging into your WSL environment.

ubuntu config --default-user root

Now that you’ve elevated your permissions, you can go ahead and run passwd ubuntu to change your password. exit a few times to leave the WSL once complete.

To get back to logging in as ubuntu or your default user, run ubuntu config --default-user ubuntu and you’ll be good to go!

All commands in sequence (from Windows command prompt) skipping input and output:

whoami [assuming it's ubuntu]
ubuntu config --default-user root
passwd ubuntu [enter password in prompts when asked]
ubuntu config --default-user ubuntu

Hope this helps someone out there!

The Value Of Good Web Design

I came across an article on one of my favourite blogs/websites and thought I’d share. I encourage everyone who reads this to continue on and read the original article as well.

I, Website

I was having a conversation with a friend recently about the value of being unique in video game creation. The conversation led me to think about how I evaluate different things in my life. I found myself asking questions I may not have thought to ask myself when making assessments. Should we value unique idea more than ideas that are recycled? What if the execution of the recycled is better than the original? Should we give appreciation to those that create, or those that revolutionize?

Our conversation and the above article made me think about the way programmers create in modern society. We live in a world where open source affords us the incredible ability to steal ideas and cheat our way through solutions, but find ourselves contributing to the community instead. We find dedicated communities that build amazing solutions to problems that we all have, and are all able to share in the value of a finished project.

That left me to think about how we build websites (or anything with code, really). Are we stealing every time we use a code snippet or open source project? Should our work be devalued for using an existing solution to supplement one of our own? Where do we draw the line, as developers, in saying that something is built from scratch? Can we consider anything built from scratch?

As we build better creation tools, higher level programming languages, abstracted development processes, scratch becomes farther and farther from where we started. For example, tools like Sass and Less allow us to create CSS programmatically and save time. Does this mean the final product has a lesser value because we were able to complete it with greater ease and in less time? Should we assign it a greater value, considering the extra time and effort that went into learning the tools? The answer seems pretty simple when it comes to investing time into learning another language, but where does that answer land when we look at website building tools like Squarespace?

I’ve seen web developers go from writing lines of HTML, CSS, and JavaScript for hundreds of dollars to dragging and dropping widgets for thousands.

I guess it all comes down to the end result.

What’s in a name? That which we call a rose
By any other name would smell as sweet.

Hello World

I’ve finally decided that I would like to have a blog.

Why a blog? Mainly, I’d like to resolve and track problems while having a recorded set of instructions that I can visit when the problem eventually turns up again. Partially, I’m getting tired of all the nonsense on social media, and would like a more intellectually stimulating outlet to air my thoughts.

That leaves me with the task of writing my first blog and setting the tone for future blogs to come. To that, I say what I’ve been conditioned to output on any primary run.

Hello World!