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 –
# 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)
# 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
# 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]