Cleaning up an infected PHP server (Mal/Badsrc-M – Troj/PHPShll-B)

I recently discovered that a number of sites of mine were considered unsafe by Google, Firefox, Yandex … The reason was they had detected malware being served to visitors of the site. I checked a bit further and I discovered it was the Mal/Badsrc-M – Troj/PHPShll-B trojan. In each of my (WordPress and other) PHP files, the first line had been changed to

<?php /* */ eval(base64_decode("...(bad stuff)"));?><?php ...
The file is easy to clean up: you remove the eval statement and that’s it. Only, on this server several hundreds of PHP files (WordPress, MediaWiki, …) were affected. So I made a script to go through all of them and clean up. It uses the fact that

  • the whole injected statement is on 1 line
  • no ‘decent’, trustworthy program uses eval(base64_decode(" ... ")) in its PHP code
  • it moves the second <?php to the second line and then removes the whole first line

So if you have the same problem, use a bash script like this and run it in the root of all your websites:

DrupalPress: Matt vs Dries

On my left side: Matt Mullenweg:

  • Matt was born in 1984 in Houston, Texas.
  • Amongst other things (see below) Matt is a passionate photographer.
  • In Jan 2003, unhappy with the capabilities of B2/Cafelog, he starts with the development of what will grow to be the hottest blog platform software around: WordPress.
  • In October 2004 he moves from Houston to San Francisco to work for CNET on, amongst other things, WordPress.
  • In October 2005, he leaves CNET too concentrate on WordPress and also launches Akismet, a (comment/trackback) spam detection platform (with plugins for e.g. WordPress).
  • In November 2005 Matt launches, the (free) hosted WordPress provider.
  • In Dec 2005 Matt annouces the creation of AutoMattic, the company behind, Akismet.
  • Matt is cited as #16 on PCWorld’s list of “50 Most Important People on the Web”

At my right hand: Dries Buytaert:

I especially like the ‘spam detection’ detail. If this is the main concern of two of the leading CMS platforms, you can imagine spam is a real problem.

If we extrapolate on the previous similarities, we could expect:

  • something like – a freemium hosted Drupal provider. The free version gives you an instant site with some standard themes (layouts) and plugins. If you want your own domain, or a custom layout, you will have to pay.
  • a Mollom plugin for WordPress – because there is already an Akismet plugin for Drupal
  • WordPress starts releasing ‘distributions’: a special version for e.g. NGO’s, for schools, for music groups. This distribution will contain the latest core of WordPress with some plugins, themes, widgets, pages … pre-installed.

In any case, I admire both guys and hope they continue to successfully lead some of the most promising web software platforms around.

Blogger snafu: emergency migration to WordPress

One of the reasons why I have been posting less the last couple of days, is because I was working on a migration from Blogger to WordPress. I was still working out some DNS stuff (don’t let me get into that, it’s complicated stuff , to do with how Bluehost‘s -my hosting provider- DNS management works).

So I was just writing a piece on how Google bought Writely with my w.bloggar local client, and when I publish I get an error: “Post was saved as draft, please log in to to publish it“. Weird, never have that normally. Anyway, I log in, get the Blogger CAPTCHA ‘word verification’ box and I publish. But I see no changes on I publish again. Nothing. Then I click the ‘View Blog’ tab in my Blogger interface. This is what I see:

Blogger Fuck-up

  • my blog is now published to some new awkward blogspot location.
  • my template is gone
  • the new template advises me to discover

Continue reading Blogger snafu: emergency migration to WordPress

Migrating from Blogger to WordPress 2.0

Ever since I saw the new ‘import from Blogger’ functionality in WordPress 2.0, I’ve known I would eventually migrate my main blog. Blogger is a great way to start blogging , but I want categories, easy template updating (without republish) and all the WordPress plug-in sweetness. As a dress rehearsal, I migrated my Dutch poetry blog first: Zo helpt Poezie ….


  • The site was managed with Blogger but published via FTP on one of my own domains. Because my old hosting system did not support domain mapping while serving multiple domains, I had to publish each domain in a subfolder. All blog’s files were stored under
  • The individual posts (one poem per post) were saved as /poezie/[YEAR]/[MONTH]/[TITLE].html (e.g. /poezie/2004/04/02/kwijt-bart-moeyaert.html). I always used “[POEM TITLE] ([POEM AUTHOR])” as title for a post. Since Blogger removes special characters, this means that the file name typically ends with the author’s last name (something I will try to use later).
  • The monthly archives were saved as /poezie/[YEAR]_[MONTH]_01_gedichten.html (e.g. /poezie/2006_02_01_gedichten.html).


I have taken an account with For $6.95 they offer 10GB storage, 250GB bandwidth and the excellent CPanel/Fantastico combo to easily configure sites, install software and manage your DNS.
My Bluehost hosting is on I use it already for stuff like the podcast feed validator and other small Smoothouse development projects.
Another option is $7,99 per month, 20GB storage, 1TB bandwidth(!) but a less handy management panel. Don’t pay more than this.


Setting up WordPress with Bluehost is quite easy: you go to the Fantastico page, select WordPress, decide on a subfolder name (in my case: “poezie”), click “Install” and all the rest is automatic. After this, the blog is installed on -in my case- Later I will have to map the poetry site to this folder (without the /poezie folder showing)
Even if you don’t have the Fantastico wizard, WordPress is one of the easiest programs to install. Then take one of the standard templates


On the new blog, go to the /wp-admin/import.php page, and give you Blogger username/password. Then select the Blogger Blog you want to import and then let the import wizard run. It will import ALL POSTS and ALL COMMENTS! This is friggin’ awesome! It might take 5-10 minutes if you have a large blog.


Now download your full archive (via FTP with e.g. FileZilla) to your local drive and upload them to where they should be after you moved the domain. In my case: I uploaded them to which will be mapped to once the DNS transfer is done.
The reason for this: all your posts will have new URLs and you don’t want people who find your old URLs in Google and click on them to get a “Error 404 not found” page. So you start by copying them to the new hosting server. We will do some more fancy redirect stuff later.


Now comes the tricky stuff: you want your domain name to point to the new host. So you edit the A or CNAME record for the domain name. This will take somewhere between 1 and 24 hours to propagate.
In my case (Bluehost) this also meant I had to transfer DNS management for all subdomains to Bluehost (i.e. change the SOA records). Bluehost requires you to this because the whole DNS management is linked to the Fantastico wizards. In this case it just meant that it took a while longer. I then mapped the domain to map to the same /poezie folder I just created.
Once that the transfer is done, all your URLs should continue to work (since you took care of that in step 4)!


Change WordPress root path to instead of (WordPress will adapt all links on the blog pages). I removed the index.html from archive root ( because a lot of sites link to it and replaced it by a index.php that redirects to
OPTIONAL: you can play with Apache Redirect/Rewrite rules to take every visitor to one of the old URLs automatically to the new URL. What I tried was:

### for the archives: easy to do!
RedirectMatch permanent /poezie/([0-9][0-9][0-9][0-9])_([0-9][0-9])_01_.*html$$1/$2/
### for the post pages: this would have worked if Apache didn't have a bug
#RedirectMatch permanent /poezie/([0-9][0-9][0-9][0-9])/([0-9][0-9])/.*-([a-z]*).html$$1/$2/?s=$3

I tried to use the fact that the author’s last name (a quite ‘unique’ word) was the last word before the .html to construct queries like: (which shows all posts from Feb 2006 with the string ‘tellegen’ in the text – which almost always translates into 1 post). However, due to a bug in Apache (the ‘?’ before the querystring is always translated into %3f and this results in invalid URLs) I haven’t found the right way to do it yet. I could have used
RedirectMatch permanent /poezie/([0-9][0-9][0-9][0-9])/([0-9][0-9])/.*html$$1/$2/ but this maps onto a whole month – or up to 10 poems. Maybe I’ll find some other trick.


Change your Feedburner source to the new URL. Everyone that’s subscribed stays subscribed. Ain’t that neat? You don’t have a Feedburner feed? What, you only had Blogger Atom feed? Shame on you. Go get one!