In WordPress, xmlrpc.php
is an API that can be used by e.g. the WordPress mobile app to communicate with the website and perform certain actions. However, its bad design also allows an attacker an efficient way to attempt brute-forcing the WordPress admin password, and if your site allows comments and/or pingbacks, a way to add comment/pingback spam to your site.
If you don't use a WordPress mobile app or the pingback functionality, you might want to completely disable xmlrpc.php
.
However, just disabling it at the level of WordPress might not be enough: since a spammer/attacker typically generates a lot of requests, passing them all the way up the stack through Apache and the PHP interpreter to actual WordPress code can require significant load even if WordPress just denies the request. As a result, you'll want to perform the rejection as early as possible.
Rejecting it in Apache is a simple string match operation in compiled, highly optimized C code, which can be very efficient. Doing the rejection at the level of WordPress involves the PHP interpreter and possibly also WordPress's database, making the rejection operation much more costly in terms of CPU power needed.
In the configuration of Apache 2.2 (or 2.4 with the legacy access control syntax module enabled) you could do it by adding a block like this to the <VirtualHost>
block of your site:
<files xmlrpc.php>
order allow,deny
deny from all
</files>
Using Apache 2.4's newer access control syntax, it will be:
<files xmlrpc.php>
Require all denied
</files>
Using fail2ban
to block the attackers sending such requests at the kernel level (using iptables
controlled by fail2ban
) would be even more efficient, but since most such attackers have multiple IP addresses at their disposal, you would likely see the attack source starting to move from one IP to another in an effort to get a number of attempts in before each new IP is blocked. A block at the level of Apache will ensure that all requests for xmlrpc.php
will be blocked.
The disk throughput spike you're observing might be essentially all from writing all the log messages for all those rejections.
I had a similar problem once, and then the customer complaint was first that Apache was limiting traffic: because of all the spammer's attempts, legitimate traffic was getting pushed aside. When Apache's resource limits were adjusted, then WordPress's database started crashing because of the sheer amount of requests (it was located on a pretty low-spec system). Blocking the source IP just caused the source to move to another IP and resume flooding after a few hours. Blocking xmlrpc.php
at the level of Apache was the easy fix, and a while later the attacker noticed their efforts were fruitless and stopped trying. But there will always be others...