Your site is hacked. What to do next? A lot of people will tell you just to restore a backup. But what most people do not take into account is that the original hack and the deployment of all malware isn’t always on the very same moment.

There’s a trend (that has surfaced and increased in popularity over the last 2 years) where a hacker finds a vulnerability, exploits it and injects a backdoor into your WordPress site. Next, they wait a couple of weeks or months. Once they’re sure you no longer have a non-infected backup, they use this backdoor to deploy the real malware to your website.

At this point, restoring a backup has become entirely useless. That’s why it’s better to clean your site than using a backup as a fallback (as you’d also be restoring the backdoor that allows the hacker to infect your site again afterwards).

So let’s learn how to clean your hacked WordPress site.

Steps to clean your hacked WordPress website

To make sure your WordPress website is back to its original state in no time, here’s the list of steps to take to get your WordPress website cleaned:

  1. Replace all WordPress core files
  2. Replace all plugin files
  3. Replace all theme files
  4. Scan for remaining malware
  5. Automate all of the above with WP Sweeper
  6. Change all passwords
  7. What about the database?

Replace all WordPress core files

Lots of malicious code gets hidden in between the core files of WordPress, so replacing them entirely is a faster way of cleaning the malicious code than fixing each infection manually.

First, check in the backend of WordPress which version you are running. You could also use WP-CLI to verify this, using this command:

wp core version

Of course, if your site was hacked to pieces (throwing fatal errors for example), there’s a big probability that WP-CLI will no longer function, as it too relies on PHP. In this case you can still look into this file to see your exact version number:

wp-includes/version.php

Next, you’ll need to go to the WordPress releases archive and download this exact version. Extract this archive and have it ready to be deployed. Now you’ll need to remove all of these files and folders:

folders:

  • wp-admin
  • wp-includes

files:

  • index.php
  • wp-activate.php
  • wp-blog-header.php
  • wp-comments-post.php
  • wp-config-sample.php
  • wp-cron.php
  • wp-links-opml.php
  • wp-load.php
  • wp-login.php
  • wp-mail.php
  • wp-signup.php
  • wp-trackback.php
  • xmlrpc.php

Attention:
Make sure you do not delete wp-config.php as it contains all configurational info of your WordPress site. You’ll need to check the content of the wp-config.php file manually for malicious additions.

Replace all plugin files

The same tactic will need to be applied to the plugins. You’ll want (and need) to replace each individual plugin with a freshly downloaded version of the exact same release. So we’ll need to identify the current version of each plugin first.

Ideally, you’ll have WP-CLI working, so you can just run this command:

wp plugin list

This will then result in output like this:

+-----------------------------+----------+------------------------------+----------+
| name | status | update | version |
+-----------------------------+----------+------------------------------+----------+
| brave-payments-verification | active | none | 1.0.4 |
| hello-dolly | inactive | none | 1.7.2 |
| jetpack | active | none | 10.5 |
| koko-analytics | active | none | 1.0.28 |
| litespeed-cache | active | none | 4.4.7 |
+-----------------------------+----------+------------------------------+----------+

That gives you each version number in an easy list.

However, in cases where using WP-CLI isn’t an option, you’ll have to verify the version number of each plugin manually. To do this, you’ll need to go into this folder:

/wp-content/plugins

There you’ll find a subfolder for each individual plugin (although some plugins are sometimes just a single php file in the aforementioned folder).

Go inside each of the folders and open the php-file the has the same name as the plugin. If we look at the content of the “koko-analytics” folder, we’ll see this:

/www/wp-content/plugins/koko-analytics# ls
CHANGELOG.md assets data koko-analytics.php phpcs.xml src vendor
LICENSE code-snippets koko-analytics-collect.php migrations readme.txt uninstall.php views

Here we’ll need to open the “koko-analytics.php” file. In the beginning of the file, you’ll find this standard structure, containing the version:

/*
Plugin Name: Koko Analytics
Plugin URI: https://www.kokoanalytics.com/#utm_source=wp-plugin&utm_medium=koko-analytics&utm_campaign=plugins-page
Version: 1.0.28

So now we know we’ll need version 1.0.28.

Next, we’ll go towards the plugin page on WordPress.org (https://wordpress.org/plugins/koko-analytics/), right-click the “Download” button and copy the button link. This gives us the following:

https://downloads.wordpress.org/plugin/koko-analytics.1.0.28.zip 

Paste this into the address bar of your browser, alter the version number if needed and press the enter key to download the correct version files.

Now we just need to replace the plugin folder under /wp-content/plugins with the newly downloaded version. Just like with the core themes, I’d suggest removing the plugin folder completely and then uploading the new version to the same location as the old plugin folder.

You’ll notice this is a lot of work, but sadly it is very necessary to effectively clean infections hidden within plugin files or folders.

For premium plugins this could also mean logging into the developer’s site (or a plugin store such as Envato) to download the correct version.

Replace all theme files

Just like with the plugins, we’ll need to replace all theme files with new versions of the same theme release. Here we’ll need to check this folder:

/wp-content/themes

Inside this folder you’ll find (again) a subfolder per theme. Inside that specific subfolder for that theme, you’ll see a style.css file. When you open it, it will start with this default structure:

Theme Name: Rams
Text Domain: rams
Theme URI: https://www.andersnoren.se/teman/rams-wordpress-theme/
Version: 2.0.0

This tells us we’re using version 2.0.0 of the “Rams” theme. Now we can go towards the WordPress.org Theme Repository and get the correct version of the theme. To do this, we’ll search for “Rams” first. Click the “More info” button on the “Rams” preview image.

Next, right-click the “Download”-button. Copy the link on that button and paste it in the address bar of your browser. This will result in something like this:

https://downloads.wordpress.org/theme/rams.2.0.0.zip

Now alter the version number and press the Enter-key. This downloads the correct version of the theme.

Extract the downloaded zip-file, remove the original theme folder and deploy the newly-extracted folder to the location of the original theme folder.

With premium themes you’ll need to consult the site of the developer or the store where you bought it to get the correct files for the release.

Scan for remaining malware

Once you’ve replaced all core-, plugin- and theme-files, I’d suggest running a scan to see if any other files were injected or added elsewhere. You could install the Wordfence plugin for this and use their scan functionality.

Automate all the above with WP Sweeper

WP Sweeper Lifetime Promotion (until January 31st 2022)

While it is perfectly okay to do all of the above actions manually, I love automating things. That’s why I’ve developed the WP Sweeper – Automated Cleaning Script. It was announced on my blog earlier this month.

This script will automate these tasks and quickly detect the core-, plugin- or theme-version. It will then connect to the WordPress.org repositories and download the correct releases for you. It will extract the release-files and replace the current files with new versions. And as an added bonus, it will add all actions to a logfile.

Did you know I’ve got a LIFETIME Promotion running until January 31st 2022? After this WP Sweeper becomes a yearly subscription based tool, so get it now to lock in lifetime use with a one-time payment.

Change all passwords

When a hacker succeeds at adding files or editing files within your WordPress site, it implies the hacker has access to disk. This means your wp-config.php is also potentially compromised. Since the wp-config.php file contains your database credentials, the database is at risk too.

So to avoid further abuse, I’d suggest changing these passwords:

  • Database password (don’t forget to update wp-config.php afterwards)
  • The passwords of all users
  • FTP-password (if it was included in the wp-config.php)

What about the database?

What if your database was altered by the hacker?

Sadly, this would depend on how the database was altered and is far harder to automate. I haven’t successfully cracked this workflow yet, so I wasn’t able to automate this yet. This also means I still check the database content manually for malicious additions.

Great indicators to assume your WordPress database was compromised are:

  • Redirects from your site to spam/malicious sites
  • Added users

The redirects usually indicate javascript code added to each element in the “posts” table and thus needs to be checked manually.

Added users can be checked using WP-CLI using this command:

wp user list

If malicious users were added, you can delete them using this WP-CLI command:

wp user delete $username

Here you’ll replace $username by the username of the actual user you’d like to delete.

It’s a wrap!

That’s about it. These are (in short) the most essential steps to clean a hacked WordPress. I hope this helps you fix your hacked WordPress site.

All the best,

Brecht