Defcon:Blog Keklkakl blog blag

3Oct/140

WordPress XMLRPC is a liability

This week I re-launched my blog, and I really wanted to do so silently, without the useless "Oh look, I've upgraded" type of post that so many publish (including myself in the past). But I was hit by a very common abuse-vector that prompts me to write a few words about it. The problem: DoS via WordPress XMLRPC. I've installed WordPress 4.0, a version where flaws in the XML-RPC mechanisms allowing it to be used as part of bot-nets and the like are supposedly resolved. But, after having my new WP installation active for less than 24 hours, my server ground to a halt, with ridiculous load numbers (190+ load), all caused by accesses to /xmlrpc.php

What is XML-RPC anyway?

The XML-RPC API is used by WordPress for a few things. The useful part, is making third-party publishing and administration applications for both desktop and mobile. But it is also used for so-called "pingbacks" and "trackbacks", where WordPress itself notifies other WordPress installations that links to their content has been created in articles/posts/pages. As this mechanism is supposed to run without user intervention, it's done without authentication, unlike the third-party client enabling admin/publish features of the API.

Insecure by default

Before WordPress 3.5, the XML-RPC API was something you had to actively enable. So to be able to use the API for publishing clients and/or pingbacks and trackbacks, you had to be aware of that the API existed, and enable it. For a number of reasons, I think that was a really good idea. Perhaps primarily because the XML-RPC used to have some seriously big flaws that could be used as vectors for abusing a WordPress installation. Now, from version 3.5, most of these flaws have been fixed. And with that, someone decided that users of WordPress are not very bright, and having to enable an API before using a third-party client was very complex and too hard for the users to understand. So they enabled the API by default. And removed the option for turning it off easily! How can possibly having an open API for anonymous, un-authenticated generator of HTTP-requests enabled by default, with no filtering, be a bad idea, right?

Well, the answer to that question is of course "WTF are you thinking??".

XML-RPC as a source of DoS and DDoS

The whole thing gets even better when we add on a need to parse XML on every one of those unsolicited pingback calls. The blog-engine is written in a language with horrible XML performance, PHP. This does lead to things like memory exhaustion via xml-rpc pingbacks. A nicely crafted XML call that requires oversized or recursive expansion of entities can easily eat up RAM and CPU. And that's before the request is later echoed to the "originator", but the originator is naturally spoofed in the request, sending it to a different host.

By sending pingbacks that "originate" from a spoofed host, we can easily create a DDoS or amplification method. Having WordPress XML-RPC be insecure by default, we get a Very Large Botnet! So not only can we cause a DoS against a box by eating up it's CPU and RAM through PHP, we can use what's left over of capacity to do the same to tons of other boxes! All without having to identify ourselves! Brilliant design!

Why do we still have pingbacks?

Getting traffic to your site, to get views and through ads or sales generate revenue is naturally important. Back when blogging was fresh and a growing new thing, the most efficient way to increase your visibility, was to have a high number of links to your content. Pingbacks and trackbacs enabled this without user intervention. You got a link pointing to you, by simply linking to their content. Now that the rage of early blogging is over, the automated trackback links are commonly seen as nothing more than spam. It's even allowed a new kind of site, the splog. In my opinion, and I share it with others, it's time for pingbacks to go away.

My site is being killed, what can I do?

If you end up, like I did, as a victim of XML-RPC abuse, you have a few options. First among the options, is deploying ModSecurity. I believe my friend over on www.NetCraWlr.net will be doing a write-up related to that. I was not ready to take that plunge, so I went with one of the other options. If you, like me want a quick-fix right now, or you want additional control, you'll have to decide if you need the XML-RPC API at all.

Ok, I want the API, what do I do?

If you want to be able to use the API for third-party applications, you can follow the recommendation from WPTavern. Finding the functions.php file of your theme, add the following code:

add_filter( 'xmlrpc_methods', 'remove_xmlrpc_pingback_ping' );
function remove_xmlrpc_pingback_ping( $methods ) {
   unset( $methods['pingback.ping'] );
   return $methods;
};

This will remove the pingback function, while allowing any other part of the API to work. The WPTavern approach works with minimal impact across most recent PHP versions. Notice however that you may still be vulnerable to XML parser exploits, unless you combine this with mod_security.

I don't need the API, let me get rid of it!

If you do not intend on using the XML-RPC API at all, you can go the drastic route and removing it completely! As there is no longer an option for turning it off in the administration interface, your options for doing this is by either adding a plugin to do it for you, or bypassing WordPress completely and telling the webserver to not process the requests.

By telling the webserver to ignore the requests, you get an added bonus: any call to xmlrpc.php will never enter a PHP parser! This reduces the server workload enormously! I have gone with this route, but I actually wanted to be able to investigate so-called "self-pingbacks", so I needed to allow WordPress using it's own local xmlrcp.php. As always, there are more than one route to get this working. I'm using Apache, and I've gone with statements in my blog .htaccess file:

<Files "xmlrpc.php">
  Order Deny,Allow
  Deny from All
  Allow from 127.0.0
  Allow from ::1
  Allow from localhost
  ErrorDocument 403 "no"
  ErrorDocument 404 "no"
</Files>

This effectively says «For any call to any file called xmlrcp.php, reject the request with a 403 message contaning nothing but the characters 'no'. UNLESS the request comes from the local host. If xmlrpc.php does not exist, do the same but with a 404.»

For the Files section to work, you need to be allowed the Limit override. If you are using pretty-url's your Directory stanza in apache's configuration will probably end up containing something like:

   AllowOverride FileInfo Limit 

A bonus of "simply say no", is that the amount of work needed to handle requests to /xmlrpc.php will have VERY low impact on your server, as only tow extra bytes are transferred, and they go back to the actual originator.

Effects of disabling xmlrpc.php on WordPress 4.0

When I was being hit by requests to xmlrcp.php, with no filtering enabled, and pingbacks disabled in the admin-interface, I was seeing a load on my server above 190. That's 190 process always waiting for the CPU to become available. After adding the above Files section, and still receiving the same volume of requests, I'm seeing a load number of 0.01. On a box doing way more than simply running apache. Currently my highest source of load is my IRC client irssi 🙂

Comments (0) Trackbacks (0)

No comments yet.


Leave a comment


Trackbacks are disabled.