My web logs are filled with requests for
/xmlrpc.php, even on sites that aren’t running WordPress. Every one of these attempts is from a scanner trying to find, and possibly exploit, WordPress sites.
Why not put those scanners in a fail2ban jail and block them from further communication with your web server?
Fortunately, someone else had already done most of the work here:
Using Fail2ban on wordpress wp-login.php and xmlrpc.php
I made a few changes to the suggested filter. For example, on this site (osric.com) there is no
/wp-login.php, but there are other instances of
wp-login.php in subdirectories. Additionally, I am seeing primarily spurious
GET requests in my access logs. I modified
filter.d/wordpress.conf to look for both
POST requests for these WordPress-related files at the site root:
[Definition] failregex = ^<HOST> .* "(GET|POST) /wp-login.php ^<HOST> .* "(GET|POST) /xmlrpc.php
I also made a couple modifications to
[wordpress] enabled = true port = http,https filter = wordpress action = iptables-multiport[name=wordpress, port="http,https", protocol=tcp] logpath = /var/log/custom/log/path/osric.com.access.log maxretry = 1 bantime = 3600
maxretryto 1 so that IP addresses will be banned after the first bad request.
- I removed
findtime = 600because that’s the default setting in fail2ban’s jail options.
- I increased the
bantimefrom the default (10 minutes) to 1 hour (3600 seconds).
The other change I made was to add
/xmlrpc.php to my
User-agent: * Disallow: /wp-login.php Disallow: /xmlrpc.php
If a malicious user creates a hyperlink to osric.com/wp-login.php, well-behaved robots should avoid it. This way I’m not inadvertently banning Googlebot, for example.
It feels really good to slam the door in the face of these scanners! But unfortunately I have to ask…
Does this do any good?
I analyzed some of the server logs from before I implemented this block, and as it turns out, most of these are drive-by scanners: they are checking for the presence of a potentially vulnerable page, logging it, and moving on. They are basically gathering reconnaissance for future use.
If a host makes a couple
POST requests in the span of one second and then leaves, banning the host’s IP won’t be very effective.
Also, I know that fail2ban is useful for brute-force ssh attempts, but how useful is it for scanners requesting WordPress files? According to my fail2ban logs, over the month of July, 2019:
- sshd: 69,771 IPs banned
- WordPress: 4,538 IPs banned
wp-login.php isn’t quite the target I thought it was. That is, not compared to
In any case, it still feels good to block a questionable scanner. Running the following command and viewing the IP addresses that are currently in jail is satisfying:
sudo iptables -v -L f2b-wordpress
7 blocked right now! Take that, suspect IP addresses!
What else can we do to block or prevent WordPress scanners?
A few ideas, none of them earth-shattering:
- As mentioned in a previous post (Using blocklist.de with fail2ban), the scanner IPs could be shared with a service like blocklist.de
- Instead of blocking the IP, I could deliver a large file via a slow, throttled connection. This would slow down the scan, but not by much. (One of my colleagues informed me that this practice is called tarpitting.)
- I could deliver a fake WordPress login form so that the scanners would accumulate unreliable data. Again, this might slow them down, but not by much.
If you have other ideas (even if they aren’t very good!) let me know in the comments.
I would like to thank @kentcdodds for inspiring me to dust off this blog post (out of my many unpublished drafts) with his tweet:
Hey, my site doesn't use WordPress, but I get a lot of traffic to wp-login.php anyway. So…
Why don't you go ahead and try it. See what happens 😘
— Kent C. Dodds (@kentcdodds) July 30, 2019
Go ahead. Visit https://kentcdodds.com/wp-login.php. I think you’ll enjoy it.