Nov
I was poking around in Wordpress's source code the other day and couldn't help noticing the insanity which is its XML-RPC pingback method. At least in 2.6.2, it doesn't seem to make much of an attempt to sanity check source URIs that are submitted in a pingback request, and is quite happy to download anything you ask of it. So what does this mean to an unsuspecting blog owner?
It means that at the end of the month you might receive a bill from your hosting provider for hundreds of gigs of data which you didn't download.
Here's how it can happen:
- Attacker creates an XMP-RPC pingback call with a target URI of one of your blog posts, and a source URI of any arbitrary file download hosted on any arbitrary download service's server (eg. download.com).
- On receipt of this pingback call, Wordpress diligently checks a few things: whether the target URI is a post that exists on your site, and whether that post is pingback enabled.
- If the above two tests pass, it proceeds to download the source URI blithely in full. It does this to check if the source URI is, indeed, linking to the target URI (a good thing), but it assumes that the source URI will be a friendly, small, processable HTML page (a bad thing).
- Lather, rinse, and repeat.
I did some calculations. A realistic average size of an XML-RPC pingback call is about 500 bytes. With that 500 bytes, an attacker can easily cause your server to download over 5 MB. Much more if your PHP memory_limit setting is the default 32 MB. Let's take 5 MB as an example. With 500 bytes of attacker traffic that is a ratio of 1:10000, meaning it'd take an attacker only 10 MB of internet traffic to get your server to consume 100 GB of internet traffic. And that's with the paltry example of 5 MB.
Some technical details
I wrote a command line Bourne shell pingback client which makes testing this easy. Feel free to grab a copy of it here (don't expect a howto showing you how to use it - use the source, luke).
Here are some example responses from a wordpress blog I tested this on:
POST sent, awaiting response... HTTP/1.1 500 Internal Server Error Content-Length: 211 Content-Type: text/html Server: Apache/2.2.8 (Ubuntu) mod_python/3.3.1 Python/2.5.2 PHP/5.2.4-2ubuntu5.3 with Suhosin-Patch X-Powered-By: PHP/5.2.4-2ubuntu5.3 <br /> <b>Fatal error</b>: Allowed memory size of 134217728 bytes exhausted (tried to allocate 123994961 bytes) in <b>/www/blog/wp-includes/functions.php</b> on line <b>1091</b><br />
That is Wordpress's xmlrpc.php script keeling over when trying to download a 130 MB file into memory.
POST sent, awaiting response...
HTTP/1.1 200 OK
Content-Length: 390
Content-Type: text/xml
Server: Apache/2.2.8 (Ubuntu) mod_python/3.3.1 Python/2.5.2 PHP/5.2.4-2ubuntu5.3 with Suhosin-Patch
X-Powered-By: PHP/5.2.4-2ubuntu5.3
<?xml version="1.0"?>
<methodResponse>
<fault>
<value>
<struct>
<member>
<name>faultCode</name>
<value><int>32</int></value>
</member>
<member>
<name>faultString</name>
<value><string>We cannot find a title on that page.</string></value>
</member>
</struct>
</value>
</fault>
</methodResponse>
This is probably the response you want. Wordpress successfully downloaded a 10 MB file and tried to search for a <title> tag in it, but naturally couldn't find one since I told it that the source URI was a download link to Spyware Doctor AntiVirus. :)
Keep in mind Wordpress logs XML-RPC requests, as does the web server.
For blog owners, I suggest disabling Pingback in your Wordpress blogs until Automattic address this.
Update: I was searching for anything like this in the past, and it looks like I'm not the first to discover it. What's bizarre is that the Wordpress team know about it but haven't patched it in current releases over a year later. Go figure!