In the previous post WordPress application hacked 1/4 – Immediate damage control, I explained what to do immediately after a security breach is detected. In this article we’ll be looking specifically at the wordpress platform and the quickest way to get it healthy and operational again.
Introduction
There was tight coordination with our customer to fulfill their needs as best possible. For the actual platform recovery a substantial amount of the (technical) workload fell on my plate. However, if there are things the customer knows better, let them do it and don’t figure it all out yourself. As an example, the platform described here has a lot of specific functionality and thus functional testing was best done by the application maintainers on their end. This combined effort speeds up the recovery and thereby re-enabling their services sooner.
Overview
One tip before we dive in: If you cannot establish with 100% certainty that a component used during recovery is clean of any malicious infection, assume it is not. When for example you use a backup of a compromised system. What you restore from that backup will thus restore to a compromised situation still.
For completeness, these are the steps you should at least perform for a full platform recovery. As a reminder, this was about a WordPress platform, so these are somewhat tailored to that:
- Review user accounts
- Review strange and dated plugins and themes
- Get to a clean base WordPress installation
- Assert that your code is clean
- Review and check all content files
NB: As stated in a previous article. If your platform holds credentials to for instance external API services, reset those passwords or keys as well.
After shutting down the service and isolating it from the public, there’s steps you should take on a higher level first. These are things like reviewing user accounts and checking themes and plugins. After that you need to clean out the files and possibly the database. Although the latter is not always at risk, there are known cases out there that describe risks therein as well. Via an external (or internal code) trigger, malicious code can be pulled from the database, placed back in memory or file. This can re-open a backdoor for the hackers. Your mileage may vary, but better safe than sorry.
Review user accounts
In coordination with the customer we checked all the user accounts. Consider the following steps to go through:
- Remove all suspicious accounts
- Remove any dated accounts
- For the ones still in use, force a password reset
In case of needing more forensic evidence you could also check if access rights were changed based on previous user access roles (assuming you have those stored somewhere).
Note: Always use email accounts on your company’s domain name. This way you always have control of the mailboxes (for e.g. password reset emails). When email or accounts are hacked that are on a personal email address, there’s now way of knowing whether certain security policies are enforced and if such accounts are hacked. It is by all means not called a personal email address for nothing.
Strange plugins or themes
Looking at strange themes and plugins is one of the ‘higher level’ assessments you can do. Check and compare them possibly with a recent backup, or better yet and acceptance or test environment, to see if they were previously there. Mind you some hacks could be already in your platform for a while but under the radar. So make sure you assert that anything pulled from a backup is absolutely free from malicious code.
$ wp plugin list +-----------------------------------------+-----------+------------------------------+-----------+ | name | status | update | version | +-----------------------------------------+-----------+------------------------------+-----------+ | acf-customizer | active | none | 0.3.0 | | advanced-custom-fields-pro | active | available | 6.0.7 | | disable-application-passwords | active | available | 1.7 | | google-analytics-dashboard-for-wp | active | available | 7.20.0 | | wp-optimize | active | available | 3.2.19 | +-----------------------------------------+-----------+------------------------------+-----------+
Note: The WP CLI command requires SSH access to where the website is hosted.
This output from the WP CLI command lists al the plugins and their state. You can of course check this via wp-admin as well. To be certain you should also compare this list with the plugin directores found in “./wp-content/plugins/”. Review this for your website and look for suspicious items and cleanup while you’re at it. Check for:
- Weird plugin names (verify them with the vendor or on wordpress.org)
- Plugins without a version
- Disable and remove plugins if you don’t use them
- Remove all disabled plugins since they weren’t used anyway
You can also do this with your themes. There should be just two themes installed. Your active theme obviously. I also advise you to have latest original wordpress theme installed. This is for testing things on any regular day when you’re troubleshooting issues. Make sure to remove all the others.
A clean WP installation
There’s a major trade off to consider when aiming for a quick recovery. If you can quickly assert that your files are clean you can leave them in place. Otherwise a wipe and reinstall of WordPress also does the trick and is often faster. Then you know for certain the installation is clean, and you can start to rebuild from there. The main goal is to focus on the result and how to get there quickly.
However, to satisfy my curiosity, I wanted to know if any wordpress files were infected. The simplest way to check this is to use the WP CLI command again to check the integrity of the installation.
# wp core verify-checksums Warning: File doesn't verify against checksum: wp-includes/cron.php Warning: File doesn't verify against checksum: wp-includes/plugin.php Warning: File doesn't verify against checksum: wp-includes/blocks/file/view.min.js -- SNIP -- Warning: File should not exist: wp-includes/js/thickbox/themes.php Warning: File should not exist: wp-includes/js/thickbox/.htaccess Warning: File should not exist: wp-includes/js/dist/server-side-mh.js Warning: File should not exist: wp-includes/js/crop/.htaccess Error: WordPress installation doesn't verify against checksums.
This gives you an immediate summary whether or not all files belonging to WordPress are clean or not. As you can see a lot of files were added and changed so starting with a clean installation definitely was the viable option in this case.
Cleanup your custom code
If you run an extensive custom code base on top of your WordPress installation as was the case, you need a way to establish your code is clean. A quick way to do that is to store checksums of your files after any update you deploy to perform an immediate scan. However, something like that belongs more under a nightly check as part of an IDS (intrusion detection system). A better option is versioning your code with github.com or similar. Of course any code development should run a versioning scheme nowadays. That way you can safely wipe everything (besides digital content) and simply redeploy the latest stable version you have deployed on your live system.
If there’s no way to get back to a clean code base the only route is to scan and examine your code thoroughly and look for weird code or symptoms. A good option for this is PHPCS (PHP Code Sniffer), but that’s something for another article.
This article is part of the series WordPress application hacked (and how to recover!).