XML-RPC

This article is part of the WordPress guide. Read the introduction.

XML-RPC is a Remote Procedure Call protocol. It’s basically just an API using XML payloads to trigger method calls on a remote server. It allows someone from the outside to prompt your website to do and return something (which is what pretty much all remote APIs do).

It’s an old protocol, widely considered to be legacy. It was created in 1998, 2 years before the REST architecture. It was in WordPress since before its inception, as it was a part of the b2 system, which WordPress is a fork of. The protocol’s main goal was why we use APIs now – to allow internet services to communicate with each other.

In wordpress, XML-RPC has been replaced with the more modern REST API. Right now, there’s only a handful of popular services that use it, such as the WordPress mobile app or the Jetpack plugin. Unfortunately, this protocol and its implementation has proven very problematic when it comes to security, especially since it’s been enabled by default since WordPress 3.5 (and still is!).

The XML-RPC endpoint in WordPress is /xmlrpc.php. This is the “front controller” for this API. There are a large number of methods available at your disposal – some innate to the protocol and some specific to WordPress. An example payload asking for a list of all supported XML-RPC methods looks like this:

XML
<?xml version="1.0"?>
<methodCall>
  <methodName>system.listMethods</methodName>
  <params></params>
</methodCall>

Historically, there have been a lot of security problems with this API. We’re talking – privilege escalations, SQL injections, lack of capability checks, and more. It’s also relatively common for plugins to have vulnerabilities exploitable only with XML-RPC. There are, however, two types of vulnerabilities you will always hear about when discussing this API in WordPress.

1. Brute Force Amplification Attacks

Many XML-RPC methods require authentication. This is achieved by passing the login and password in the XML payload. If the credentials are invalid, the server will return a 403 response.

This, in it of itself, can be considered a vulnerability, although a mild one. It provides an endpoint for the attacker to brute force passwords while skipping security checks (such as 2FA or captcha) implemented on the frontend login page.

But that’s not what we’re talking about here. We’re talking about the system.multicall method. This protocol method allows the sender to include multiple (theoretically unlimited) methods in just one request. The idea was good – if you need to prompt multiple actions, it’s more efficient to do it in one request. But the implications of that were a glaring oversight.

With system.multicall, you could try calling a method a thousand times in one request – each time with a slightly different password. One request would test 1,000 passwords. This is crème de la crème for brute forcing.

Thankfully, this is not a threat anymore. WordPress core developers understood that it was a big deal and changed their XML-RPC implementation (against the protocol’s specification) so that, with system.multicall, if an authentication fails – all further authenticated methods fail as well. Their credentials are not verified. This change was introduced in WordPress 4.4.

2. Pingback DDoS Attacks

Another troublesome method in XML-RPC is pingback.ping. This method is supposed to notify a website that another website has linked to their blog post.

Here’s how it works:

  1. The owner of website A writes a blog post and links to a post from website B.
  2. Website A sends a pingback.ping request to website B. The payload includes the source (a link to the new post on website A) and the receiver (a link to the post on website B that was linked to).
  3. Website B receives this request and checks that website A is not lying. It sends a GET request to the source URL to see the linked URL with its own eyes.

All is fine until you realise that you can spoof step 2 without step 1. You can send a pingback request to any website which supports it. There’s no validation that you actually are the source website (website A).

Here’s how it can be used in DDoS attacks. An attacker gathers a huge list of websites that support XML-RPC and pingback.ping (which isn’t going to be hard considering it’s the default configuration). I’ll call these sites “mules” from now on.

For each of the mules, they send an XML payload with the source being a link to their DDoS target, and the receiver being any link on the mule’s website. The mule follows step 3 – it tries to verify that the link is actually there.

What this leads to is thousands of legitimate websites making GET requests to one server. Each of these “mules” (which are just normal WordPress websites) just became a part of a botnet DDoS’ing the target website. The target website will almost certainly go down, especially if the targeted URL is a large resource or results in heavy computation.

Best part? The real attacker’s IP never even hit the target’s server. It only contacted the mules, and it didn’t have to send many requests to each of them either (maybe even as few as one). It’s also hard to rate limit such an attack. All of the IPs are different, and they are usually legitimate servers that shouldn’t be blocked.

Unfortunately, this vulnerability can be utilized to DDoS anybody – not only WordPress websites. The target doesn’t have to support XML-RPC. It’s the vulnerable “mules” that are causing harm to third party websites.

By the way, don’t think that, just because you aren’t the target, you should not care to not be the mule. Remember that each of these requests drain your server’s bandwidth. Perhaps even more importantly, it can lead to your IP being blacklisted or even to violating the ToS of your hosting provider.

Disabling XML-RPC

Unless you or any of the plugins on your site are actively using XML-RPC, it’s a best practice that you disable it completely. It’s a legacy feature with many security holes and really no benefit.

There are a couple of ways you can disable XML-RPC on WordPress. The easiest one is with plugins. Many security plugins have built-in features allowing you to disable it with one click.
However, a better approach is to deny all requests to /xmlrpc.php at the web server level (e.g., in .htaccess). According to a WPScan article, many plugins only disable XML-RPC methods that require authentication, leaving other methods (like pingback.ping!) still working. That’s because they (incorrectly) use the “xmlrpc_enabled” filter, which doesn’t disable “anonymous” methods.