Also known as “How to hack your own website”.
Sometimes you need to log into WordPress as an administrator but don’t have the means to do so. Working for an agency at my 9-to-5, this happens all too often. The client, or potential client, wants you to do some work on their website but doesn’t have any information to allow you to help you help them. Asking for “control panel” access (aka: Plesk, cPanel, or something similar) is met with confused looks and/or mutterings, and all the client knows is “this is what I have for FTP access if I want to upload something”.
Disclaimer: Running code which automatically takes a site visitor and logs them in as a admin user is a potentially dangerous operation. Use this code at your own risk, obviously I accept no responsibility for anything that should happen from you using it.
Fortunately, access to the website via FTP is all you need to gain Administrator access to the WordPress admin area. All you need is a little code:
The Code Itself
<?php if ( $_SERVER['REMOTE_ADDR'] == "255.255.255.255" ) { function auth_redirect() { // Overriding this function means no reauth is ever required } require_once(ABSPATH . 'wp-includes/pluggable.php'); //Retrieve by user role $arrAdmin = get_users( array( 'role'=>'administrator', 'number'=>'1', 'fields'=>'ID' ) ); $intAdminUserID = $arrAdmin[0]; $user = get_userdata( $intAdminUserID ); wp_set_current_user ( $user->ID, $user->user_login ); wp_set_auth_cookie( $user->ID ); do_action( 'wp_login', $user->user_login ); }
Hopefully that is all fairly self-explanatory. [Update 7/30/15: Additions made to override the auth_redirect() function, and by default the example now demonstrates how to restrict this functionality by IP address] First we call `get_users()` and ask for a single record back, only asking for the ID field where the user role is Administrator. Assuming nothing has gone wrong with your WordPress installation, you should have at least one administrator user in the system. We set `$intAdminUserID` to the value of that user’s ID, and then set `$user` to a user object returned by the `get_userdata()` function.
The final three lines do the rest of the work for us. Now that we have our hands on a user it is trivial to set the current user, the auth cookie, and execute the `wp_login` hook. And just like that, you’re in! As long as you can run this code in your browser within WordPress, you just successfully logged into the system.
Implementing the Code
Seems easy, right? But how do we make this code execute? You can do it in a number of ways if you have access to FTP, but personally I prefer to utilize the often-overlooked `mu-plugins` functionality of WordPress.
While one could certainly modify the `functions.php` file of a site’s active theme, I prefer to implement this code as a Must Use Plugin simply because I don’t like touching code I don’t otherwise know. If I can do all of my work on the side of everything that is already installed on the website, all the better.
The features list of Must Use Plugins are all you need to know why this is a perfect method of executing our code:
- Always-on, no need to enable via admin and users cannot disable by accident.
- Can be enabled simply by uploading file to the mu-plugins directory, without having to log-in.
- Loaded by PHP, in alphabetical order, before normal plugins, meaning API hooks added in an mu-plugin apply to all other plugins even if they run hooked-functions in the global namespace
WordPress has given us the ultimate way to execute arbitrary code right inside the WordPress ecosystem. And in fact, the `muplugins_loaded` hook is the very first hook loaded in WordPress, immediately after all `mu-plugins` have been executed. What that means is that nothing else running on the site can interrupt what we want to do, so there’s typically no worries about code conflicts from anything else that may be installed.
Simply take the code sample above, and create a new `logmein.php` file (or whatever you’d like to call it) with that PHP code. Save it & upload it to the `/wp-content/mu-plugins` directory – you will likely need to create the `mu-plugins` directory here yourself, since WordPress does not create one by default. Note: make sure you upload your php file to the root of `/mu-plugins`: Must Use Plugins do not support plugin code within nested directories like the normal `/wp-content/plugins` directory does.
Now visit your website! You’ll notice that you are immediately and invisibly logged in to the website, since you will see the Welcome Bar across the top of the browser window. Congratulations!
Protecting the Code
Of course, running this code completely “naked” has a few obvious pitfalls. For starters, you just put something on the website which will log every single user in as an administrator. So how can we harden this at least a little bit?
The options are really up to you. Generally speaking, I will implement a combination of IP detection with a querystring variable check. That way I know that this will only execute if the site visitor is coming from my IP address, and only if the request contains a specific key/value pair that only I know. The code for that would look something like this:
if ( $_SERVER['REMOTE_ADDR'] == '127.0.0.1' ) { if ( isset( $_GET['auto'] ) ) { if ( $_GET['auto'] == 'qwerty12345' ) { // Do our magic login stuff here } } }
In Conclusion
Be smart with this code. Use it for good. And always, always, always clean up after yourself. Once you have gained access to a system, either reset the password for an existing account or create a new account for yourself and then delete this code from your server.
Good luck, and happy coding!