In a previous blog post (Fail2ban + Tarpit), I explained how to setup a Tarpit for Fail2ban to use it against the attacker that got banned multiple times. It works great especially in conjunction with WP Fail2ban, a fail2ban plugin for WordPress.

Later on, I moved this website to CloudFlare, by doing so I rendered one my security mechanism inefficient.

WP Fail2ban

This plugin simply log the failed login attempts to one of the system log like /var/log/user.log or even the normal syslog. You can also set a group of user that should be logged directly when there is an attempt on it like “admin”. It’s useful to find the bot attempting to login into your admin panel with a default username “admin”.

I set up 2 different jail, one for failed login attempts and one for login attempts from blocked source.

You can find all the information on how to setup this in the documentation of the plugin: Installation steps

Problems

By using CloudFlare, it means all the traffic to the website is first sent to CloudFlare then to my server. Which means, my server only get connections from CloudFlare. This poses 2 problems for fail2ban.

No more visitor IP

The first one being the lack of real IP of the visitor, since only CloudFlare is connecting to my server, this can be easily resolved and I’ll explain how. The second problem I faced is directly linked to the resolution of the first one. Even with the real IP of the visitor, fail2ban won’t be able to ban the “visitor” (understand

Real IP useless

Even with the real IP of the visitor, fail2ban won’t be able to ban the “visitor” (understand bot) trying to connect as admin to my WordPress since it’s coming from CloudFlare IP’s. And obviously banning it as I was doing before with TARPIT won’t have any effect.

Solutions

To resolve those problems, I first setup Nginx to gather the real IP of the visitor, CloudFlare does provide a header with this information.

Secondly, I created a script to interact with CloudFlare API to use their firewall to ban an IP.

Getting the real IP

Configuring Nginx for doing is is pretty easy. Add this file to your conf.d directory. It contains all the CloudFlare CIDR, IPv4 and IPv6.

Now Nginx will send, to your different application, the right IP

CloudFlare Firewall

The script I created directly use the API v4 of CloudFlare to ban the IP directly for your website but adding a captcha. I prefer to put the captcha because a bot can’t pass it (thanks reCAPTACHA) and because if it’s a legitimate user, he’s not completely banned from accessing the website.

Then I created a new action for fail2ban to automatically add and remove IP ban in CloudFlare. The last part was to assign it to the wordpress-hard rule in jail.d. (Or any other jail you setup in your configuration).

Script

To use my script you need to have JQ installed. I’m using it to parse the response from CloudFlare API when wanting to remove a blocked IP.

sudo apt-get install jq

Don’t forget to make the file executable (chmod +x). I placed it at  /usr/local/sbin/cloudflare-firewall

Fail2ban Action

Put this file in your action.d directory. You also need to edit it to add your CloudFlare username, API Key and ZONE ID. You can find all of them in your CloudFlare profile. The ZoneID is the ID assigned to your domain by CloudFlare. You can override this default in each one of the jail you create by given parameter to the action.

Fail2ban Jail for WP Fail2Ban

And the last part is to set your jail to use the new action like this:

[wordpress-hard]
enabled = true
filter = wordpress-hard
logpath = /var/log/auth.log
port = http,https
maxretry = 1
action =cloudflare-firewall[name=wordpress-dangerous]
bantime=86400

Here you go, you’re again protected against those bots.