So Your WordPress Installation Has Malware

I manage the technical side of 1 More Castle. So far, I’ve had to clean out malware on our WordPress installation on several occasions. The most recent one was the most debilitating, as it was enough to have Chrome throw an error before actually showing the site:

The latest malware to affect 1 More Castle

In light of the time required to fix this issue, I decided to write up a short post on some common places or things to check when tackling a malware/black hat SEO issue. This tutorial will assume you are using a web host that supports SSH or another command line interface, and use Chrome as your primary browser.

Legal crap: don’t blame me if things blow up on you while fiddling in the command line. These are just tips for stuff I’ve figured out as I’ve explored how our WordPress install was infected. We good? Cool.

Step One: Replicate the problem

  • Take a screenshot of the issue
    • Good to have for reference later
  • Get the source code of the issue (Right click on page, View Source)
    • This is the source as it arrived from the server, without JS changing
  • Use the Chrome Dev tools and copy the code into a text file
    • This is the DOM structure as Chrome interprets it after JS modifies it. It could be wildly different from the original source, so it’s good to get a comparison.
  • Turn off JavaScript using the Chrome Dev Tools
    • This is useful for visually understanding how JavaScript enables (or doesnt!) the hack.

Step Two: Take it Offline

You should immediately take your site down. This could be as advanced as having a maintenance plugin, or as simple as changing a few files.

To take your site into a quick and dirty maintenance mode, create an index.html file and place it on the root of your site. This file can be as simple as you like, but it would be advisable for it to say something to the effect of “Sorry, it’s broken, but we’re working on it”. The second and final step of this is to modify the .htaccess file. This is the file that routes all requests through WordPress, which is why your url could be, when there is no file by that name. Each line in the .htaccess file should be commented out, which means that something that looked like this:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress

now looks like this:

# BEGIN WordPress
#<IfModule mod_rewrite.c>
#RewriteEngine On
#RewriteBase /
#RewriteRule ^index\.php$ - [L]
#RewriteCond %{REQUEST_FILENAME} !-f
#RewriteCond %{REQUEST_FILENAME} !-d
#RewriteRule . /index.php [L]
# END WordPress

A passable error page

First strategy: finding changed files

If an attacker has changed files in WordPress, it might be able to be tracked through the OS’ “last modified” property on files and folders. The unix command

ls -lt

will list all the files and folders in the current directory with lots of extra info per file, including their last modified date. Additionally, it will be sorted from most recently edited to most distant edit.

If you’re able to find out files that are modified at odd times, it will give you somewhere to start from.

Searching your directory structure

While not foolproof, this is a useful way to find simple hacks. If your malware is writing some extra content to your pages, be it Black Hat SEO or otherwise, there needs to be a source of this content. It could either be in the database or in traditional PHP files, but the latter is more likely.

grep "pills" -rli ./

grep is a standard unix command for searching through files. In this case, it’s searching for the string “pills” in the current directory, and all child directories. The options “rli” refer to:

  • searching directories recursively.
  • list only the file names. Normally grep would output the line where it is found as well, which I find disorienting in larger searches.
  • ignoring cASe rEQuIrEmenTs

Files to check

If automated searches are coming up negative, the malicious code might be obfuscated in some way, so you may need to do some file combing. Here are some files you may want to check first:

  • **wp-content/themes/***
    • We had a Black Hat SEO attack that actually injected an entire fake drug store into one of the wordpress default theme directories. Clicking on links in the drug store would redirect to an identical, but real, store off-site.
  • index.php
  • wp-config.php

If you see large blocks of unintelligible code, it’s likely junk being written out to your page that doesn’t want to be found through automated searches. Download a local copy of WordPress, or browse the source on GitHub to compare the original stuff against your files to see what shouldn’t be there.

A suspicious as fuck file

Cleaning Up

  • Add new auth keys to your wp-config.php file by copying the generated code on WordPress’ site.
  • Generate a new database password. I would recommend getting a fancy 20-character randomized string from This password will need to be changed on your web host as well as in wp-config.php file.

Know a better way? Let me know in the comments!

Grunt doesn’t run on Sails Lift

If you’re encountering an error like this using SailsJS:

agentsubterfuge@Ashmac:~/Desktop/Review a Great Game Day 2013/reviewagreatgameday$ 
node app.js
error: Grunt ::
    throw err;
Error: Cannot find module '/Users/agentsubterfuge/Desktop/Review\ a Great Game Day 2013/reviewagreatgameday/node_modules/sails/node_modules/grunt-cli/bin/grunt'
    at Function.Module._resolveFilename (module.js:338:15)
    at Function.Module._load (module.js:280:25)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:901:3

The solution is due to the spaces in your directory structure. Apparently Grunt disagrees with them. Removing the space in the directory name on my desktop worked out.

Web Development, Gaming, Toronto

baskets new balance pas cher

chaussures new balance pas cher

chaussures new balance femme

chaussures new balance homme

chaussures new balance belgique

chaussures new balance trail

chaussures new balance enfant

chaussures new balance pour marathon

new balance 574 pas cher

new balance 410 pas cher