Fail2Ban and Brute-Force Password attacks on WordPress

I maintain a server hosting a fair number of WordPress blogs and I get inundated with brute-force password attempts.    In order to minimize the likelyhood of success of an attack, I have taken to limiting the number of login attempts I’ve customised some Fail2Ban rules to provide “overriding” lockout of accounts.

The code certainly has its limitations – for example it will – without warning –  temporarily lock out people who have forgotten their passwords, however for the most part it works pretty well.

One of the things I’ve noticed recently is that some attempts are persistent – they will continue to try log in even when null-routed, and for long periods of time.  I’ve thus written a second rule which looks through the fail2ban logs and bans – for an extended period – anyone which has been banned more then a few times.   This further reduces the likelyhood of a compromise, and also reduces the amount of “fail2ban spam” I receive, ie notifications of a ban being put in place.

Additionally, I’ve come up with a custom rule to ban IP’s sniffing around for a wordpress site where none exists.

The appropriate Fail2Ban rules are as follows –

apache-wplogin.conf

# Fail2Ban configuration file
#
# Author: Tim Connors
# Tweeked by David Go
#

[Definition]

# Ignore specific client who often forgets password.
ignoreip = XXX.XXX.XXX.XXX

# Option:  failregex
# Notes.:  Regexp to catch Apache dictionary attacks on Wrodpress wp-login
# Values:  TEXT
#
failregex = :80 <HOST> -.*(GET|POST).*/wp-login.php.*(HTTP)
:443 <HOST> -.*(GET|POST).*/wp-login.php.*(HTTP)

apache-wp-probe2.conf

# Fail2Ban configuration file
#
# Author:  David Go
#

[Definition]

# Option:  failregex
# Notes.:  Regexp to catch Apache dictionary attacks on Wrodpress wp-login
# Values:  TEXT
#
#failregex = <HOST>.*] "POST /wp-login.php

failregex = \[client <HOST>\] script \'/PATH/TO/VIRTUALHOSTSl/(.*)/wp-login.php\' not found or unable to stat

persistentban.conf:

# Fail2Ban configuration file
#

[Definition]

# Make sure we never lock ourselves out.
ignoreip = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

failregex = fail2ban.actions: WARNING.* Ban <HOST

And, of-course, the appropriate lines in jail.conf

[apache-wp-probe]
maxretry = 3
findtime = 180
bantime = 14400
enabled = true
port    = http,https
filter  = apache-wp-probe
logpath = /var/log/apache2/error.log
action  = iptables-multiport[name=wpprobe, port="80,443", protocol=tcp]
sendmail-whois[name=wpprobe]

[apache-wp-probe2]
maxretry = 3
#findtime = 14400
bantime = 14400
enabled = true
port    = http,https
filter  = apache-wp-probe2
logpath = /var/log/apache2/error.log
action  = iptables-multiport[name=wpprobe2, port="80,443", protocol=tcp]
sendmail-whois[name=wpprobe2]

[persistentban]
maxretry = 3
enabled = true
filter = persistentban
findtime = 3600
bantime = 86400
logpath = /var/log/fail2ban.log
action = iptables-multiport[name=multiban, port="80,443,21", protocol=tcp]
sendmail-whois[name=multiban]