Post-mortem of a WordPress hack
Few days ago we had to help a good e-commerce customer running on our Magento platform with a few hijacked WordPress sites. A redirection code was embedded into the theme and visitors were sent to a random gambling site. It wasn’t a good look.
To protect the site from other known and new attacks in the future we upgraded it to the latest WordPress version, tightened access rights to WordPress files and made the database read-only.
In the first part of this post we will show what files attackers modified in our WP installation and how they redirected user to a target site. In the second part you will find how to make your WP installation more secure.
Post-mortem of the attack
Most likely the attack was automated and attackers used a known vulnerability in WordPress to inject a piece of obfuscated PHP code into
footer.php file of the theme. The obfuscation was made by shifting ASCII codes by 1 position, gzipping it and encoding the result with base64:
De-obfuscated code (the code styled by us for readability):
By default this code adds a piece of JS code into the footer which adds an overlap with a button to hide the original content of the page. Clicking on the overlap or its button re-requests the current page with
pagerd_ query parameter which triggers a redirection to the target site in the injected PHP code. But it does nothing like that if the WP page is requested by Google or some other site crawler.
The script also remembers users which were redirected by setting a cookie in their browsers.
The obfuscated PHP code also allows attackers to check and update the target site using specially crafted requests to WP.
URL of the target site was stored in a text file with a random name (
.SIc7CYwgY in our case) in the root directory of WP or in
/var/tmp/ directory and was also obfuscated (XOR + base64)
Tightening WordPress security for static sites
The content of these sites is updated so infrequently that they can be treated as static sites. A prudent thing would be to convert them to static HTML pages, but there was no time or budget for that. We upgraded WP to the latest version and did following 2 steps to make it more secure:
Tightening file system access rights for WP is described at https://codex.wordpress.org/Hardening_WordPress#File_Permissions . That page has other useful recommendations for making WP more secure.
We also prepared a simple shell script based on those instructions to automate the task. This script should be run as root so that file ownership changes can be set correctly.
NOTE: some 3rd party extensions may require write access to some directories to function correctly. Please, check documentation for the plug-ins you’re using before making file system changes.
Locking the DB is done manually by running the following SQL commands in the WP database. Make sure you have sufficient rights to execute grant and revoke instructions in MySQL.
Replace the placeholders in the script with actual data:
* – the database name of your WP instance
* – the database user of your WP instance
These commands basically reset any access rights for WP database user and then give it minimal rights required for WP site functioning. Also in the 3rd line we allow full access for the table used by W3 Total Cache plug-in.
Run following SQL instructions to unlock WP database (see
wp-config.php in the root of the WP site):
- Anything that can be hacked will be hacked
- Plugins with write access to the file system add cost
- It’s cheaper and easier to have WordPress to auto-update itself
And the best piece of advice is to convert your CMS site into a static HTML site if you don’t update the contents often. We hear that Jekyll is painful to set up, but once up and running you can save your WP as HTML5 and upload to the web server for hosting.