New WordPress attack: POST /wp-admin/maint/repair.php


Update: I received the following reply from Dion Hulse speaking on behalf of the WordPress project in response to my email to security@wordpress.org. He points out what should have been obvious to me: the malware is probably probing for details about the database schema in hopes of crafting SQL injection attacks.

The 'pass' and 'p2' parameters have never been used, nor have any effect, on the maint/repair.php script. It's possible that these could be used by a plugin though.

The script in question is a tool for when a database has become corrupt, and user-logins are no longer possible (for example, the user table has crashed), because of this, no user authentication is handled on the request.

The authentication which the script relies upon is the existence of the 'WP_ALLOW_REPAIR' constant, which a remote user cannot trigger, only someone with code-level access to the server can.

My assumption here is that they're searching for WordPress installs which have incorrectly left the script open and available, they could use this to discover the database table prefixes, which in itself doesn't give them much details, but could be used to get a more reliable SQL Injection through a vulnerability in a plugin. The chances of all these aligning is very small though.

The following trac ticket has a few improvements which could be made to this script:
https://core.trac.wordpress.org/ticket/11717 

Today I logged a new attack against my WordPress installation. Malware is now issuing POST /wp-admin/main/repair.php (and rrepair.php) requests. The data in all four requests is the following:

pass=asldkjsdfhoiuer3u98iuefghkjdbvmnbkjhas398&p2=ZWNobyAieHh4ISEheHh4Ijs=

WordPress quite unhelpfully returns a 200 (OK) HTTP status even though the request was rejected. This is something about WordPress that really irritates me. It frequently reports a OK HTTP status when in fact something went wrong; e.g., an authentication failure. In this particular case the failure is because I have not enabled the feature. How did I learn this? I created a file named wp-repair-post.req with the content of the request sent by the malware:

POST /wp-admin/maint/repair.php HTTP/1.1
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Content-Length: 74
Host: www.skepticism.us
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: /wp-admin/maint/repair.php
Cookie: wordpress_test_cookie=WP+Cookie+check

pass=asldkjsdfhoiuer3u98iuefghkjdbvmnbkjhas398&p2=ZWNobyAieHh4ISEheHh4Ijs=

I then manually sent that request to my web server:

nc localhost 80 < wp-repair-post.req

The output from WordPress helpfully told me:

To allow use of this page to automatically repair database problems, please add the following line to your wp-config.php file. Once this line is added to your config, reload this page.

define('WP_ALLOW_REPAIR', true);

I then enabled that feature and reissued the request. This time WordPress returned a HTML page that included a button with the link repair.php?repair=1. So I modified the request to include that query string.

Holy shit! Even though the passwords in the post are completely bogus WordPress reported that it did in fact perform a repair:

The <code>blog_users</code> table is okay.
The <code>blog_usermeta</code> table is okay.
The <code>blog_posts</code> table is okay.
The <code>blog_comments</code> table is okay.
The <code>blog_links</code> table is okay.
The <code>blog_options</code> table is okay.
The <code>blog_postmeta</code> table is okay.
The <code>blog_terms</code> table is okay.
The <code>blog_term_taxonomy</code> table is okay.
The <code>blog_term_relationships</code> table is okay.
The <code>blog_commentmeta</code> table is okay.
Repairs complete. Please remove the following line from wp-config.php to prevent this page from being used by unauthorized users.

<code>define('WP_ALLOW_REPAIR', true);</code>

The /wp-admin/maint/repair.php URI performs no authentication. WTF! Who in the hell thinks an unauthenticated administrative interface is acceptable in the year 2015?

What is unclear is why the malware is probing that URI. On the bleeding edge WordPress 4.2.3 release I’m running the “pass” and “p2” parameters appear to be ignored. Are they utilized on earlier versions? If so then these probes might be a way to verify whether a password is valid. Is the malware simply trying to overload the site with database repair activity? Whatever the case I’ve opened an enhancement request to make this interface authenticate the request and filed a security report with security@wordpress.org.