The week started out so good! I migrated the site over to what I felt was a more robust back-end and site design only to be hacked he very next day. A bit ridiculous if you ask me. Here’s how it went down:
At about 4 in the afternoon on Wednesday I recieved an email from my server-side mail account here: [email protected] The message was an automated dump from WordPress that told me that the password had been lost and recovered for my “admin” account. I’ve seen a few of these lately because I ran GeekApproach in a beta mode on a different domain to make sure I got everything right before flipping the switch and going “live”.
So, mistake #1: Ignoring an automated email from your system telling you that your password has been changed. I signed in about 7 PM to see my site still in my theme, but garbled text. I’m now attributing this to (a rather excellent plugin) WP-SuperCache showing me a static version of the page. In attempting to log-in however, it appeared my old password wouldn’t work. Refreshing the main page brought me a “This site has been hacked by:” message proclaming the hacker to be “mosleium” (which I don’t believe) and that my data was apparently intact somewhere.
I lightly freaked out– I thought someone had penetrated my root account on the server, not just my WordPress sub-apps, but possibly other more critical things running. This turned out to be the case. I successfully logged into cpanel on my box, and hopped into phpMyAdmin to go talk to my mySQL dbases online. Once there, I got into the users table where the passwords are stored– they are stored in an MD5 hash which is one-way encryptable (I’ll do a post about that later), but the recovery email address field– that is, the email address a new password gets sent to had been changed to some clearly unauthorized user. I forced an update to the table back to one of my email addresses, and was able to “recover” my password back to myself.
Once in, I couldn’t see any sign of the hacker. I found my root index.php page overwritten with his content however, and restored my site from the beta/backup site. Rebuilt SuperCache, done. Now, to figure out why and how this happened.
I searched around and found a few signs of how the exploit works. Firstly, it looks like it worked in WordPress 2.8.*– I’ve been running 3.1.* trunk for awhile now. It sad to see that it wasn’t fixed in my most recent copy. Based on the above sight, I ended up changing my wp-login.php file to something a bit different. Simply put, you can pass in an array as a key value here which the system will interpret as being correct and allow you to reset the pass without confirmation. I’ve changed the few relevant lines of code in the file, and now it looks like this:
$key = $wpdb->get_var($wpdb->prepare("SELECT user_activation_key FROM $wpdb->users WHERE user_login = %s", $user_login));
if ( empty($key) || is_array ($key) ){
// Generate something random for a key...
$key = wp_generate_password(20, false);
do_action('retrieve_password_key', $user_login, $key);
// Now insert the new md5 key into the db
$wpdb->update($wpdb->users, array('user_activation_key' => $key), array('user_login' => $user_login));
The critical part here is the if ( empty($key) || is_array ($key)) line which stops an empty array from being passed in as a key.
So, with that fix hopefully I’m ok. It sucks that I’ll need to make that change everytime I update WP because they’re still not including that as a fix yet.