WordPress 2.8.3 Remote admin reset password
blog.sucuri.net
blog.sucuri.net
$user = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->users
WHERE user_activation_key = %s", $key));
How does that line of code retrieve a valid $user? I looked at the bug fix which filters out the $key being an array, and that will prevent you from passing an array, but I don't see how the array gets you over the hurdle above.UPDATE: yes, user_activation_key is an empty string when WordPress hasn't received a request from a user to do something that would require it to be set.
http://news.ycombinator.com/item?id=755244
It's worth noting that this has already been patched on trunk and the latest stable branch (2.8), so if you run svn update now you'll get this fix.
http://core.trac.wordpress.org/timeline
The patches there are also more extensive. I would recommend getting it direct from the WordPress svn repository rather than using random third-party patches.
These are the commits so far, in sequence. As we can see, the erroneous blacklist approach has been replaced in [11799] by a whitelist one (is_array replaced by !is_string).
http://core.trac.wordpress.org/changeset/11797
http://core.trac.wordpress.org/changeset/11799
http://core.trac.wordpress.org/changeset/11801
http://core.trac.wordpress.org/changeset/11802
http://core.trac.wordpress.org/changeset/11803
(Note that these are just the changes on trunk, not the commits to the 2.8 stable branch, which are identical.)
That said, I missed it on the first pass. He could have prepended "Source:" to the link to further clarify.
In PHP, GET and POST arguments that look like arrays are automatically converted to arrays. So "key[]=" in the query string has the result that $_GET['key'] = array('');
empty(array('')) = false, because the array has one element.
$wpdb->prepare uses the PHP function vsprintf, which has undocumented behaviour when it gets an array as an argument. The (undocumented) behaviour is (apparently) that if the contents of the array are concatenated together and treated as a single string.
The code that calls $wpdb->prepare in this exploit intends to do the latter, but because there is only one argument which happens to be an array, it ends up that the former is used.
do_action('retreive_password', $user_login); // Misspelled and deprecated
do_action('retrieve_password', $user_login);
Isn't this a verbatim example from the "Signs you are a bad programmer" list from a few days ago? Code that does nothing but is left in anyway to "make sure it all works".But in a static type system you will have to cast or convert query-string data to whatever you want them processed as before you can use them as anything besides plain strings.
If you want it to be an int, convert it. If you want it to be a datetime, convert it. If you want it to be an array of whatever, convert it.
If the data is not in the expected format (like in this case), the conversion will fail.
In this example we saw how modifying one query-string parameter had effects down to the signature of a function. Something like that will never happen in a static type system.