Spammers push technology forward too.

Almost a month ago I got the strangest Google Alert, it said:

Web 1 new result for "Marco Valtas"

No Prescription Needed Pain Killers And Sildenafil ... - Marco Valtas No Prescription Needed Pain Killers And Sildenafil. Men's Health. Shipping Policy, Canadian Pharmacy, Erectile Dysfunction, Stop Smoking.

Obviously something wrong had happened. I wasn't quite sure why Google thought that Canadian Pharmacy would link to my blog, but who knows? After a couple minutes digging around it became clear that something was very wrong, more and more searches on Google returned bogus links and references to my site were also from bogus links.

WordPress Spam Injection Attack

In a nutshell, spammers gain control by your WordPress platform using some vulnerability, which might be in some plugin or theme, make your site behave differently when crawled by Google (maybe other search bots too). It's pretty clever, taking the Google page rank and attacking enough sites they start to link one to another promoting the results. I had one Israel TV website linking to my site by 36 different URLs, the TV website is also run by WordPress code.

That's what happened with my site. If you dig into the Google there's stories of people having to go over all data in their sites to ensure they were secure again. And the rest of the links talk about how to secure your WordPress installation.

So I did what you expected, I saved the code for evidence and took down the site until I got some evidence that it was clean back again. Going through dumps of MySQL and the code.

Trying to clean everything

I did just enough to be relatively confident that no bad code was injected around. In order to avoid any missing file I did a simple clean install of WordPress, I could go over the missing plugins afterward but the primary objective was to clean up the website from any spammer injection.

Even after checking files, doing a bit of grep around I wasn't confident. First because I didn't know what vulnerability was exploited. Second because for some reason if I tried to access the website using the bogus URL's WordPress would only redirect to my home page with a nice 200 OK http code back. I wasn't happy and I decided to dig the code a little more, this time I was determined to control WordPress redirection in details, when I've found the Canonical API to handle WordPress Redirecting. That was the last push I needed to ditch WordPress.

Couple notes on security

Until proven contrary Security and Convenience don't walk together, they are almost opposite to each other. You can tell by paying attention on the most secure things you deal, lets say you bank account. If you want check your bank account online chances are you will need a token not only your password. You company might give you laptops and their policy don't allow you to install anything into it and other security hassles, some valid, some just theater.

Taking out the social engineering, when is code against code, one thing matters simplicity. Every operation you add to your code is one more operation to be exploited, as your software grows in complexity also grows and possible security holes and there's clever folks out there making money (it got to be money in this for exploiting my website to sell Viagra) with every invasion.

All convenience WordPress was providing me is grounded in lines and more lines of code. Themes, plugins, configuration, feeds, comments and such don't come for free security wise speaking. And frankly I didn't need all this stuff.

Going to Jekyll and plain old HTML pages

I knew about Jekyll by some blogs, I thought about going for it but I was too lazy to do so since my website, although important to me, it was not a priority until the attack. When I decided to change, my friend Chris Stevenson brought Jekyll to my attention. Jekyll seemed the right solution, just enough to get a website running and pretty old HTML would make less vulnerable to spammers. I won't put all details of migrating to Jekyll there's plenty information already in the web. Some details that made my migration a little different from the others I saw.

Backward compatibility with WordPress links

My old WordPress was configured with permanent links format like this, in order to keep old links compatible with Jekyll I needed some code to proper redirect URL's. I did a dump from the WordPress database and created a file which maps post IDs with the slugs used by Jekyll and little CGI (this exposes how old I am) script to redirect requests. I hope retire this script soon.

The dump from WordPress didn't went smoothly

This website was migrated from Blogger to WordPress, WordPress to WordPress and finally from WordPress to Jekyll. Was written in Portuguese (just a couple of posts) and English. Guess what happened? It got mess up. Old posts with weird characters that even changing encodings didn't solve, no proper formats and code snippets once formatted with SyntaxHighlighter have the old bracket tag. So I have to go back and fix them all, maybe delete some posts :)

There was a migration page which lists the old posts and their statuses of Pending or OK. For this, I created simple generator plugin for Jekyll that only checks if the tag migration is defined on the post, if so is considered migrated. Here's the script:

module Jekyll

  class MigrationListGenerator < Generator
    safe true

    def generate(site)'_includes/migrations.html','w') do |file|

        site.posts.reverse.each do |post|
          next if > Time.parse('2012-04-02 00:00:00 -0300')
          file.write("<li><a href='#{post.url}'>#{['title']}</a> #{'migration') ? 'OK' : 'Pending'}")


Every run, Jekyll loads the plugin and executes it. An annoying side effect is I can't run Jekyll with the --auto flag anymore. Since it creates a file, it recognizes the site update and generates it again ad infinitum. I had no time (or too lazy) to think in a better solution. And post.html layout has also a conditional to render a little notice if the post wasn't migrated yet (I had to remove the tag {% op %} because of formatting constraints):

if page.migration == null
<div id="migration_note">

  Looks like I didn't fix this post yet, I'm working on fixing all my posts
  after a sad hacking of my site.  You can check the progress <a


Final thoughts

Going to Jekyll wasn't bad at all, was just the timing which wasn't chosen by me but by the spammers. Other advantages are being free of DB, use Git to manage the files, using Vim to edit, a fresh look and some other ideas. Drawbacks, the only I can think right now is loosing the ability of posting from any computer with internet, now I have to push to the repository as a hook deploys the files.

And if you see anything weird on the site please let me know, as something maybe escape my sight.

Update: I finished the migrations so there's no more migrations.html page.


Published in May 09, 2012