Using the Wordpress OpenID plugin for Evil

I've been meaning to write a blurb about Wordpress and OpenID for a while, rather insignificant, yet simple evil tricks; Alas it's been on the back burner. Unfortunately I have nothing to do this weekend.

In July I was investigating a bug and found some unrecognized entries in PHP's error log. Here's an example:

[17-Jul-2010...] Successfully fetched 'hxxp://www.<removed>.com/': GET response code 200
[18-Jul-2010...] Successfully fetched 'hxxp://www.<removed>.com/': GET response code 200
[18-Jul-2010...] Successfully fetched 'hxxp://www.<removed>.com/': GET response code 200

Where the <removed> items were very odd looking domain names related to shoes. Shoes? What the hell was using PHP to download shoes? I immediately flipped out and started greping everything in existence for "Successfully fetched". I didn't think the box was compromised, as malware seldom leaves log messages. But I was worried none-the-less.

It wasn't long before I found the culprit, the Wordpress OpenID plugin. More specifically, the Yadis authentication module was downloading whatever URI was entered into an OpenID ID input field. This makes sense as XRDS is used by OpenID to enumerate available services via the remote OpenID provider. However, there are a few issues. Rohan, of Times New Rohan (not going to link to his blog as it has a low WOT rating :O), noticed the logs on his box a few years ago. He thought the random (and invalid) OpenID provider lookups were related to spam. This makes sense; as in my case, it now appears that my IP visited domains looking for new shoes. If I was a spammer I could collect Wordpress blogs using the OpenID plugin and increase traffic to my clients without involving humans. Of course I'd be cheating my clients, but who cares?

Evil ability 1) Use OpenID service endpoint discovery calls as a spammer to increase hits to client websites.

Alright, that's not too bad, and what can you really do about it? OpenID allows for distributed providers, anyone can be their own OpenID provider, why not a site selling shoes? Don't worry, more evil examples will follow. Though is there a way to protect websites employing malicious spammers?

Sure, tell them to inspect their visitor's User-Agents.

The OpenID plugin sets a custom User-Agent which not only includes it's own version, but the version of PHP too. And if you have CURL installed, the plugin will use CURL to download pages and append the CURL version too! Why? Not sure, but here's an example:

Note: these versions are from my test Ubuntu VM.
Without CURL: "php-openid/2.1.2 (php/5.2.10-2ubuntu6.4)"
With CURL: "php-openid/2.1.2 (php/5.2.10-2ubuntu6.4) curl/7.19.5"

Evil ability 2) Information disclosure, we can harvest PHP, OS, and CURL versions using a controlled mock-provider-host and scraping Apache access logs.

You can fix this quite easily, open (./Auth/Yadis/HTTPFetcher.php) and remove the PHP version from Auth_OpenID_User_Agent. If you're using CURL then open ParanoidHTTPFetcher.php and remove the CURL version tack-on (on or around line 126).

The next little trick is my favorite. Within the OpenID plugin is a setting for the max download size, called Auth_OpenID_Fetcher_Max_Response_KB and by default it's set to 1024, meaning 1 MB worth of XML data. That's a lot of XML! Want to make a host download a lot of zeros? Input a URI pointing to a 1-2MB file full of zeros (you can squeeze a bit more than 1 MB using Apache). I can push my default-configured Apache running in a Ubuntu VM to about 91% memory utilization in a moment with a few POST resubmissions. (Might take a bit longer depending on the host's bandwidth.) Speaking of which, you may also be able to exhaust their data transfer quota. :(

Evil ability 3) Make OpenID download a ton of useless data, filling memory, and data transfer limits.

I'd recommend to anyone using the OpenID plugin to reduce the max_response_kb out of rationality. The constant is defined in "./Auth/Yadis/HTTPFetcher.php". This will reduce malicious data transfers a bit (not too much using Apache, about 30-50% of your reduction). A rate limiter on discoveries is the correct solution.

If I missed or incorrectly reported any details please let me know!