Breaking and Entering: Restore Admin Access to WordPress

Breaking and Entering — Recover WordPress Admin Access

If you spend enough time in the business of creating and maintaining WordPress websites, there will inevitably come a time when a customer will reach out to you with a specific request: help them restore admin access to their WordPress website.

They will explain how they used to have somebody who worked on their website, but that person is now gone for whatever reason, and the customer can’t access their own website to make some important and urgent changes. Could you possibly help them out?

WordPress makes it very easy to recover an account when the user has lost their password, but how to proceed if the user doesn’t have admin access to their WordPress website?

Let’s find out what options we have.

 

Table of Contents

Disclaimer

Obviously, the very first thing you should do is make sure the request is legit. How to do that is beyond the scope of this article but my point is that you should not blindly accept to do such work and that you should always make sure you’re working with the website owner and not with a nefarious third party. Be smart!

Now that we have set this aside, let’s discuss how we can approach this mess.

In order to help a customer in a situation as the one described above, you will probably end up needing access to their hosting control panel, or FTP access to their website. But even if such access is readily available, it is worth spending 5 minutes to try a couple of low-effort things first.

After all, why try to squeeze through the chimney or the basement window if the front door is left unlocked?

Restore Admin Access: Non-Invasive Attempts

The thing I would do first in a situation like that is try to figure out if the customer does have admin access, but they have forgotten about it.

During installation, WordPress creates an admin account and — unless changed by hand — assigns it the username ‘admin’. I will attempt password recovery by going to the following URL:

https://example.com/wp-login.php?action=lostpassword

Note: in this and subsequent code examples, I will be using the example.com domain; you should of course change that to your actual domain name.

Try to restore WordPress admin access with admin username

 

Trying admin before anything else

If this account exists, WordPress will send an email with recovery instructions to the email address associated with it. If your customer is lucky, this email address belongs to them. Ask them to check their inbox. If they get a message with a recovery link in it, your job is done, but you will still bill them for the whole hour. Right?

However it is very likely this attempt will fail with an “Error: There is no account with that username or email address” message. It is a good security practice to assign a different username to the initial admin account, and these days all but the most incompetent sysadmins will have renamed it.

So let’s try something else instead.

A default WordPress installation comes with a pre-published blog post called ‘Hello World!’. The authorship to this post is assigned to the admin user. Many WordPress themes that ship with some sample data do the same.

You could try opening the ‘Hello World!’ blog post which has the post ID of 1 by typing:

https://example.com/?p=1

This URL links to the author page associated with the WordPress User ID of 1:

 https://example.com/?author=1

If the person responsible for the initial setup of this website has been careless or lazy, we have a chance to learn the username of the admin user from the authorship metadata.

The specific behavior of the blog post page and the author page is different depending on the theme and the customization settings. If you are lucky, it will show the author, and the author name might contain a link to their WordPress author page, like this:

https://example.com/author/someuser

You can try that username (someuser) to attempt password recovery and tell your customer to once again check their mailbox. If they get a recovery link, you will have been successful.

Success Rate

The stuff I described above will work only if whoever set up WordPress is an amateur or has been extremely careless. It is a universal security practice to never call the admin user ‘admin’, and most good WordPress developers will have put measures in place to block resource enumeration (that thing with ?author=1 we used).

Realistically speaking, the chances to recover admin access using the tips above are very low. But since it only requires a trivial amount of time and effort to try, I feel obliged to try this first before attempting more effective but invasive measures.

Restoring Admin Access via FTP or the Hosting Control Panel

For brevity, I will assume that the customer has already provided you with access to the web host control panel, or at the very least with FTP/shell access. There are several ways to restore admin access to the WordPress dashboard:

1. Create a new admin account
2. Reset the password of an existing admin account
3. Change the email address of an existing admin account (i.e. take over an account)
4. Promote an existing lower-level account to admin status

I prefer creating a new account, but there are different real life possibilities that might make another option preferable. This is why I will show you how to perform all operations, and I will leave it up to you and your customer to decide which one to perform.

Possible Solutions

There are two ways to achieve our task, and they both involve modifying the WordPress database.

One method is to write several database queries and execute them via php file. It is quick and effective, but not really fun to write about. Also, it is highly specific to the task at hand — any knowledge you will obtain through using it will be limited to solving the same exact problem and nothing else.

My preferred method involves using a small GUI tool called Adminer (https://www.adminer.org). While I will use it to show you how to fix that particular issue (restore user access to the WordPress admin panel), I hope you will recognize the overall usefulness of that tool and add it to your bag of tricks.

Despite the horrible name (and a UI to match…), Adminer is a very competent tool to work with MySQL/MariaDB databases. Compared with phpMyAdmin, it has a simpler interface and requires no installation: all features are contained within a single PHP file that you can deploy and delete as needed.

Where to Get Adminer

Go to adminer.org and scroll down to the Downloads section. For this tutorial, I will grab the Adminer for MySQL, English only‘ version. The ‘full’ version supports other database engines and other interface languages which are of no use for the purpose of this tutorial.

Go ahead and grab that file, then save it to the root folder of the WordPress site you need to access. I prefer to rename the file to adm.php while I am at it, because it saves time typing the URL in the browser, and does not require remembering.

Note: By itself, Adminer is harmless. It can’t do anything if you don’t have the database name, db user name, and db user password. However, it does expose the database to the world, and somebody could find a way to exploit that. That is why I take some additional precautions to restrict access to Adminer.

1. I place Adminer into a random, 8-character directory under root
2. I limit access to that directory by creating a .htaccess file in  it with the following contents:

Order Deny,Allow
Deny from all
Allow from 123.123.123.123

where 123.123.123.123 is of course my actual IP address.

3. I set a reminder to myself to delete the Adminer folder 24 hours after I am done using it.

After doing all of this, I try accessing Adminer from the browser:

https://example.com/{random-string}/adm.php

Navigating Adminer

Upon successful loading, Adminer greets me with the following underwhelming login screen:

To get past this screen, you need to provide the database name, db user and db password. You can get them from within the wp-config.php file that is located under the website root folder:

// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'Database' );
/** MySQL database username */
define( 'DB_USER', 'Username' );
/** MySQL database password */
define( 'DB_PASSWORD', 'Password' );
/** MySQL hostname */
define( 'DB_HOST', 'localhost' );

About WordPress Table Names

While viewing wp-config.php to get the DB credentials, I also suggest that you scroll down and take note of the $table_prefix setting.

/**
* WordPress Database Table prefix.
*
* You can have multiple installations in one database if you give each
* a unique prefix. Only numbers, letters, and underscores please!
*/
$table_prefix = 'wp_';

While a large number of WordPress sites use the default prefix ‘wp_’ to name their tables, there are many exceptions to this rule where the prefix is different or there is no prefix at all.

There are also cases where within the same database there are multple tables with the same name but different prefix (a plugin called WP Reset that makes database snapshots is notorious for that).

Throughout this tutorial I assume that the tables use the standard prefix of wp_, but I recommend that you check out and take note just in case.

And now, back to our regularly scheduled programming

Going back to Adminer, I suggest that you tick the ‘Permanent login’ checkbox. It will store a cookie in your browser and add an automated login link to the left:

This will allow you to close and/or restart your browser and resume work at leisure, without having to go back to wp-config.php to fetch the database settings.

Don’t Panic

“I like the cover,” he said. “Don’t Panic. It’s the first helpful or intelligible thing anybody’s said to me all day.”
― Douglas Adams, The Hitchhiker’s Guide to the Galaxy

When you see the main screen of Adminer for the first time, you might feel the urge to close the browser window and start running until you hit the ocean; then start swimming.

However I am here to help you suppress that primal panic and do the thing you came to do. Adminer looks scary only the first time, and for a short amount of time; after you have seen how easy it is to use, you will warm up to it — I promise!

First Things First: Backup the Database

This one is non-negotiable. No matter how good you are with databases, and how much experience with WordPress you have, you should only proceed if you have a fresh backup.

However, you have a choice here: either export the whole WordPress database, or only the tables on which we will be working (wp_users and wp_usermeta). This one I leave up to you to decide.

A. Full Export

If you want to export the whole table, you need to click on Export in the top left corner and select output type, format, etc. Do not forget to tick the checkboxes next to Tables and Data below the export button!

B. Single Table Export

This one makes more sense to me. As you will be working on a single table at a time (wp_users followed by wp_usermeta), you only need to make sure you don’t break any of these two tables.

Scroll down the list to the left until you find the wp_users table and click on the select link to the left. You should see something like that (without the emojis that I have used to hide sensitive data, of course):

Before you proceed, let’s do the backup first. Click on the checkbox next to the Modify column to select all rows, then select ‘save’ and ‘sql’ in the Export tab and click on the Export button to create an SQL file and save that in a safe location.

Solution 1: Create New User

To add a new entry to that table, click on the ‘New item’ link at the top right.

Restore WordPress admin access by creating a new user with admin privileges

Leave ID blank. It will auto-increment to the next lowest available number. Fill user_login (this is the username), user_nicenameuser_email and display_name. Leave the rest blank for the time being.

You next need to create a password for the new user, and store the hash of that password in user_pass. For this, I use the very convenient WordPress Password Hash Generator made available by CodeBeautify.org

When you click on the ‘Random’ button, the tool will issue a brand new random password for your new user, and will generate the hash record for it. Copy the hash (the long string that begins with $P$B) and paste it into user_pass within Adminer, then press ‘Save’ to create the new user record.

Important: Note the ID number assigned to that user — you will need it in a minute. Store the password as well.

We are almost there!

Your new user is created, but it has no role within WordPress just yet. To fix that, you must add two more records for that user: User Level and Capabilities. These details are kept in the table called wp_usermeta. You already know the drill: 

1. Locate wp_usermeta in the list on the left
2. Click on ‘select’ to the left of the table name
3. Make a backup of that table
4. Add records (this time there will be two operations)

To assign User Level, you will create a new record (click on ‘New item’):

Leave umeta_id blank. For user_id, supply the ID number of the new user. For meta_key, supply the value wp_user_level. Set meta_value to 10. Press ‘Save and insert next’ to store the record and return to the same insert screen. Adminer will confirm insertion (‘Item xxx has been inserted’).

To assign Capabilities, you will create another record.

For user_id, supply the ID number of the new user. For meta_key, supply the value wp_capabilities. Set meta_value to a:1:{s:13:"administrator";b:1;} and press ‘Save’ to store the record and gtfo.

And… you’re done! You can now try to log in with your newly created admin account via https://example.com/wp-login.php

Solution 2: Reset the Password of an Existing User

This operation requires a single operation within Adminer. Instead of adding a new record to the database, you will edit an existing record. However you first need to find out the user record to modify, and this might not be easy, if the website has many users. Here’s how to go about it:

2.1 Find Users with Admin Privileges

1. Locate the wp_usermeta table in the list on the left and click on ‘select’ next to it
2. Click on the = sign next to the meta_key column header to open the table search function and search for wp_user_level with a meta_value of 10:

This will give you a (hopefully, very short!) list of user IDs that associate with WordPress users that have admin capabilities. Keep this list open in a browser tab for the time being — you will have to go back to it shortly.
3. Locate the wp_users table in the list on the left and click on ‘select’ next to it
4. Create a backup (in case you skipped Solution 1, go back and see how to do it)

2.2 Filter Admin Users by ID

If your website has many registered users (an active blog, a membership website or a Woocommerce store…), the wp_users table might be hundreds or thousands of rows long. You will need to filter the table so that only those records who have admin capabilities remain visible. To do that, click on Search once again, and prepare the following query:

In the first field, you will select ID, and in the second you will change the equal operator (=) to IN, which looks into a list of values. In the last field, you will type the IDs of the WP admins you obtained in Step 2 (comma separated).

You should then ask your customer which profile to reset. To help them remember, send them the contents of user_nicename, user_email and/or display_name for these entries. Hopefully, they will recognize an account that belongs to them, and for which they can receive emails. If the miracle happens, go to https://example.com/wp-login.php?action=lostpassword and plug that username or email address into the recovery field; then let the customer pick their own password.

Alternatively, you could reset their password yourself (see the part about user_pass in Solution 1 above) and send them the new password over email or IM, but password sharing is a horrible practice. Don’t let any customer drag you down into this.

Side note: As you can see, I really dislike seeing other people’s login credentials. If your customer is so clueless to the extent they don’t know their own WP username, or can’t reset their own password once you help them find their username, you aren’t really helping them by resetting the password of that account. It is better to create a new admin account and stick with it, and to begin billing this customer for support and maintenance. But because customers are different (and sometimes difficult…). I am giving you options. Use them wisely!

Solution 3: Change the email address of an Existing User

You can suggest this to your customer as a means of recovering access to the admin account used by the previous maintainer. By changing the email address associated with it, the customer will be able to reset the password.

The way to approach this is similar to the one outlined in Solution 2: filter WP accounts with admin rights, send the list to your customer and wait for instructions about which account to edit.

Once they come back to you, you simply need to edit the existing record for user_email. I would also change the value of user_login.

Solution 4: Promote an Existing User Account to Admin Status

While possible and easy to implement, this is another solution that I generally dislike. Account permission levels exist for a reason. If your customer has been operating with restricted permissions before, perhaps there is no reason to change this now.

Also, sharing username/password access is still prevalent among less technically inclined users, and by agreeing to promote an existing user, you may unwittingly let somebody else in to cause trouble.

Recap

So… here is what we did in this post.

Hopefully, you helped a customer regain admin access to their WordPress website. I first showed you a couple of simple tricks to trigger password reset for an existing profile under the control of that customer. Depending on how the website was designed and configured, these might not have worked, but the time and effort involved were so low that it didn’t really matter.

I then showed you how to deploy a small GUI tool called Adminer and use it to access the database from a web browser. With the help of Adminer, you made a database backup, and then proceeded to execute one of several possible recovery scenarios (create new admin account; take over existing admin account; promote another account to admin status). I also explained why I prefer the first method to every other alternative.

By showing you how to do all of the above, I actually took you on a crash course into quick, small-scale database querying and editing, and I also lifted the curtain a bit on some WordPress internals like user permission levels. We will have the chance to talk more about these details in future blog posts.

I sincerely hope these hints will tickle your fancy and that you will end up spending some time exploring the WordPress database with Adminer to advance your knowledge about the platform.

And, circling back to the very beginning of this article (breaking and entering, remember?) I want to ask: Have you ever had to play the locksmith and break into a WordPress website? How did you do it?

Leave a comment below — I promise your secrets will be safe with me and all readers of the WPX blog!

 

Leave a Reply

Your email address will not be published.