
Proof of Concept:
http://DOMAINNAME/wp-login.php?action=rp&key[]=
Why does it reset admin?
When $key is passed an array[] it is treated an empty string. This will in turn match every user within the database. The first user just happens to be the admin, which WordPress will reset.
$user = $wpdb->get_row(
$wpdb->prepare(
"SELECT * FROM $wpdb->users
WHERE user_activation_key = %s", $key
)
);
The Issue.
It looks like empty() will treat an array as an empty string and not return an error.
wp-login.php.
if ( empty( $key ) )
return new WP_Error('invalid_key', __('Invalid key'));
The Fix.
WordPress has released a fix which is shown below. This is still a black list approach and only adds an extra check for the array.
if ( empty( $key ) || is_array( $key ) )
return new WP_Error('invalid_key', __('Invalid key'));
This is still using a black list method and I also think some improvements can be made before the query statement. I believe some blame can be put on PHP by not throwing an exception to an empty array. When time permits I would like to play around with other things that could be passed to $key. I'm still exploring other possibilities of this not just being a password reset that is sent to the admin. If anyone has some ideas, I would love to hear.
References:
http://core.trac.wordpress.org/changeset/11798
http://archives.neohapsis.com/archives/fulldisclosure/2009-08/0114.html
http://us3.php.net/manual/en/function.empty.php
http://isc.sans.org/diary.html?storyid=6934