Aug 17 2009
Wordpress remote admin reset password patch
The recent Wordpress bug that could reset the admin password seems to have been updated in the new version of Wordpress 2.8.4. Or if you are lazy like me, you can patch that bug yourself (I’m using quite old Wordpress version).
What we need is filename called wp-login.php
Try to find the function called reset_password. If you are using version 2.8.3, then the line number should be 185. Here is the code for the function without any modification:
function reset_password($key) {
global $wpdb;
$key = preg_replace('/[^a-z0-9]/i', '', $key);
if ( empty( $key ))
return new WP_Error('invalid_key', __('Invalid key'));
$user = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->users WHERE user_activation_key = %s", $key));
if ( empty( $user ) )
return new WP_Error('invalid_key', __('Invalid key'));
// Generate something random for a password...
$new_pass = wp_generate_password();
do_action('password_reset', $user, $new_pass);
wp_set_password($new_pass, $user->ID);
update_usermeta($user->ID, 'default_password_nag', true); //Set up the Password change nag.
$message = sprintf(__('Username: %s'), $user->user_login) . "\r\n";
$message .= sprintf(__('Password: %s'), $new_pass) . "\r\n";
$message .= site_url('wp-login.php', 'login') . "\r\n";
$title = sprintf(__('[%s] Your new password'), get_option('blogname'));
$title = apply_filters('password_reset_title', $title);
$message = apply_filters('password_reset_message', $message, $new_pass);
if ( $message && !wp_mail($user->user_email, $title, $message) )
die('<p>' . __('The e-mail could not be sent.') . "<br />\n" . __('Possible reason: your host may have disabled the mail()function...') . '</p>');
wp_password_change_notification($user);
return true;
}
Just update the 2nd line of the function with:
if ( empty( $key ) || is_array($key) )
for
if ( empty( $key ))
I know this is just a dead simple work around and upgrading to version 2.8.4 is the best option. One can expect more of these kinds of vulnerability in near future especially when using query string in default way (http://domain_name.tld/file.php?var1=value1&var2=value2).
Also have a look the way the above function is implemented in 2.8.4 and the bug is patched.
function reset_password($key, $login) {
global $wpdb;
$key = preg_replace('/[^a-z0-9]/i', '', $key);
if ( empty( $key ) || !is_string( $key ) )
return new WP_Error('invalid_key', __('Invalid key'));
if ( empty($login) || !is_string($login) )
return new WP_Error('invalid_key', __('Invalid key'));
$user = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->users WHERE user_activation_key = %s AND user_login = %s", $key, $login));
if ( empty( $user ) )
return new WP_Error('invalid_key', __('Invalid key'));
// Generate something random for a password...
$new_pass = wp_generate_password();
do_action('password_reset', $user, $new_pass);
wp_set_password($new_pass, $user->ID);
update_usermeta($user->ID, 'default_password_nag', true); //Set up the Password change nag.
$message = sprintf(__('Username: %s'), $user->user_login) . "\r\n";
$message .= sprintf(__('Password: %s'), $new_pass) . "\r\n";
$message .= site_url('wp-login.php', 'login') . "\r\n";
$title = sprintf(__('[%s] Your new password'), get_option('blogname'));
$title = apply_filters('password_reset_title', $title);
$message = apply_filters('password_reset_message', $message, $new_pass);
if ( $message && !wp_mail($user->user_email, $title, $message) )
die('<p>' . __('The e-mail could not be sent.') . "<br />\n" . __('Possible reason: your host may have disabled the mail() function...') . '</p>');
wp_password_change_notification($user);
return true;
}
The exploit is the typical example of HTTP Parameter Pollution. If you haven’t gone thru the slide, I recommed you to have a look. The problem is that HPP can not be defended by using anti-XSS functions like htmlentities() and htmlspecialchars(). The way query strings are handled by the respective web servers like Apache, IIS and so on also makes it difficult to present universal solution. In my opinion, the best way to defend againsts HPP is to enable mod_rewrite and restricting the way key/value pairs are routed in a URL.



