I keep updating this post as I learn more. So if you’re affected, there’s new material at the bottom. I am currently running this full sweep every day, because each day I find something different. But three days ago there were twenty things, yesterday five, and today only one, so maybe I am getting closer.
Latest news 4/25/08: blog seems secure again. But be sure to do the “secret key” thing newly listed at the bottom as well!
So, I mentioned before that I was a victim of a hack. It was a spam injection attack — the one known as the Goro injection attack. But my symptoms were slightly different from some of the ones I have seen on the net, so here’s some war stories even though I suspect the blog is STILL not clean.
First, read these two posts:
- WordPress Spam Injection: ‘Goro’ hacked my blog
- Expunging the wordpress.net.in spam injection hijack
Also read the advice from Jeff Freeman in the last post on this.
OK, in addition to that advice, I also had the following problems:
Can’t get into your admin panel
In the wp_options table, the db_version was set to 0. This prevented me from accessing the admin panel, because it demanded to upgrade the database, but 0 isn’t a valid DB to be upgrading from. The fix: use SQL or PHPMyAdmin to manually set this to the correct version for your blog. For 2.3.3, it’s 6124.
Change your admin password while you’re at it.
In addition to the advice given there, you can look for the base64 encoded obfuscated code that is rebuilding the exploits in your database. I had already cleaned out the various “rss_9sfnp9735hf097325097” sorts of things in the wp_options table. The SQL for that is on one of the links above and looks like this:
delete from wp_options where option_name like 'rss_%' and option_name not in ('rss_language','rss_use_excerpt','rss_excerpt_length');
However, these entries are being added by code hidden in another option. The Galoppini post suggests looking for blog_headers (which isn’t there in a normal WordPress install). But in my case it was in wordpress_options, inside of wp_options. Who knows what other ways they hide it. But a visual scan will show you — simply put, there shouldn’t be any things in the wp_options table that are giant blocks of numbers and letters.
In my case, even this code was extra-obfuscated — instead of “eval( stuff )” it was actually written backwards. So I suggest doing a search of your full database for “eval” and “lave.”
In my case, there’s maybe still something somewhere adding this block of code into the database, because ten minutes after cleaning out those “rss_” entries, they’re back. Edit: I was wrong: using Search within PHPMyAdmin showed 8 results for “rss_%”. But they were all things that were supposed to be there. But we’ll see what’s up tomorrow.
Second edit: nope, there were more there this morning. So there’s still something putting them in there. That means there’s a PHP file somewhere that’s injecting it — and it could be anywhere. (At this point, I have done not one, not two, but three complete upgrades of WordPress, plus overwriting all the files many times). My next step is going to be grepping all of the files on my host looking for “base64.”
Third update: Turns out that the Dashboard makes option entries of the form “rss_8324hf98hjfsa984hf” and the like. They are cached versions of the feeds on the dashboard. So you may only have the issue if the contents of the field are a giant block of base64 encoded stuff, rather than an actual RSS feed.
Search engine redirection
If search engine results for your site point to somewhere else (in my case it was ezwebdirectory), you should check your .htaccess file. It is in the same place as your index.php file. In my case, there were a whole bunch of redirects in there for every major search engine, and a clean WordPress install didn’t catch this because I normally don’t blow away the .htaccess file.
Harden your plugins folder
Edit: another thing to do: add a blank index.html to your plugins folder. Otherwise, anyone can see what plugins you have by going to http://www.yoursite.com/wp-content/plugins, and try automated attacks against them.
Edit: yet more, I’ll just add onto the bottom of this.
PHP inserted in files
There’s also the stuff that may be inserted into your header.php, footer.php, index.php, and other files. I found a PHP line in several files that didn’t belong as well, right at the top of the file. Affected files:
And it went in today, so something added it. Best way to find these — look everywhere for dates more recent than your new install.
Fake images with code
There was also a comments_old.jpeg added into the default theme and a couple of “.giff” files buried in various places. They were actually all PHP files. Delete ’em.
Check your wp_usermeta table. The tip-off was seeing that the Manage page in the admin area showed 2 administrators for the blog even though there is only one — but only on the front page of the manage users tab. Clicking on the link to list them showed just me. So I went into the database, and I found two extra user ids that had administrator permissions. One of them was a registered user named “WordPress” — the other wasn’t even in the wp_users table. I deleted these rows out of both the wp_usermeta and out of the wp_users table. Be sure to catch all the stuff — you want to identify the user Id, and delete all rows that involve that user id — the wp_capabilities, and the wp_user_level especially.
There’s a new layer of security in WP 2.5 that uses a secret key. You can read about it here:
You should get this set up!
And not done yet…
If I can’t find the offending code, I’m going to be reduced to blowing away everything, pretty much — grabbing a plain XML export of the database, doing a fresh install, and rebuilding themes while going over them with a fine-tooth comb. No fun.