___________________

Gain greater visibility into your information security infrastructure.
___________________

WordPress Password Reset Vulnerability

A recently published remote exploit in WordPress 2.8.3 has been fixed in a non-optimum manner in WordPress 2.8.4. It is definitely worth upgrading, but dissection of the vulnerability may provide some additional insight.
When someone clicks the 'Lost your password?' link on the WordPress login page (/wp-login.php) the form on the lost password page (wp-login.php?action=lostpassword) asks for username or e-mail address. This form sends an email to the address or address associated with the username - in it is a link that allows remote access via a URL path to that PHP module with a couple of parameters appended. The link will remotely access the password reset code in the 2.8.3 wp-login.php. The parameters are action=rp (for reset password) and the secret activation key.

http://mywordpressdomain.org/wp-login.php?action=rp&key=08s923Krud84ksiw...

This exploit allows an attacker to reset the password remotely without the secret activation key. If the activation key has been set (the password has been reset) the attack will fail. How and why does the attack succeed, if the password has not been reset previously? Let's look at the comments I have added to see what the reset password code is attempting to do.

function reset_password($key) { // pass the activation key string to the function
global $wpdb;
$key = preg_replace('/[^a-z0-9]/i', '', $key); // eliminate non-alphanumeric characters from the string
if ( empty( $key ) ) // check to see if the string is empty has been changed to:
if ( empty( $key ) || !is_string( $key ) ) // this new line also checks if it is not a string
return new WP_Error('invalid_key', __('Invalid key')); // if the string is empty return invalid key msg
$user = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->users WHERE user_activation_key = %s", $key)); // get user corresponding to activation key

A malicious user can submit a WordPress wp-login.php? URL with the action parameter set to 'rp' and the key value set to an empty array 'key=[]'. The empty array will pass the empty string check, but will pass a null key value in the SELECT statement to the MySQL database. If the password has not been previously reset, the first row in user database is that admin user - which will match and allow the attacker to reset the admin password.

The fix in version 2.8.4 is to checks that the key value is empty and if it is a string. At a minimum all input values should be cast to type immediately after it is input to overcome vulnerabilities due to PHP loose typing. The statement (preg_replace, above) used to eliminate non-alphanumeric characters from the string before comparing it to the database activation key is pretty rigorous, but may still leave the system vulnerable to attacks using alternate character sets.

More generally there is a need to ensure comprehensive and standardized input validation for WordPress and PHP. Done right this will address deeper potential input validation vulnerabilities - in particular addressing the 'canonicalization problem.' Canonicalization refers to the approach to resolving equivalent forms of a value to a single standard or 'canonical' value. Although PHP 6 should default to UTF-8 for outputs, given the multiplicity of character sets, without comprehensive canonicalization that encompasses both PHP and MySQL this is likely to cause additional vulnerabilities in the future. The Open Web Application Security Project (OWASP) Enterprise Security API (ESAPI) project has probably produced the best canonicalization input validation routines available across a range of languages.