“Have You Got Anything Without Spam?”

Filed under:Blogging — posted by Anwyn on July 14, 2009 @ 9:53 am

A Guest Post by Spam Killer Daddyman

Spam is usually very straightforward to manage in WordPress blogs. Almost all of it arrives in the form of comments and is quickly (we hope!) dispatched by the admin (either manually or by her spam filter). Some spammers are more devious, exploiting security holes in WordPress or mysql to embed their nastiness directly within the blog.

This blog recently began to show spam in its RSS feed. Interestingly enough, the spam didn’t show up when viewing the feed directly–only when viewing it through a reader like My Yahoo! or Google Reader. The blog had clearly been infected by some sort of malware.

RSS feeds typically deliver a short summary of WordPress posts, either inline (as in Google Reader) or when you hover the cursor over a link (as in My Yahoo!). The symptoms of this particular malware infection are that only the most recent post contains any summary text at all, and rather than displaying an article summary, it recommends the reader “Buy Aristocort…” or some other nonsense.

We searched through the WordPress files and mysql database but found no trace of the spam. We updated WordPress to the latest version, but still the spam persisted. (Anwyn aside: Therefore, the problem had to be in files that were not updated–either in the WP theme files or in the mysql database itself. Gulp.)

After quite some time of sifting through a mysqldump, I finally stumbled across something suspicious in the wp_options table: a string, hundreds of characters long, that looked like a data dump of some kind. The epiphany came when I saw the following characters toward the end of the string:

[…]cfJ3byJXZ”(edoced_46esab(lave[…]

Alter your perception a bit and read that string backwards:

[…]eval(base64_decode(“ZXJyb3Jfc[…]

This is php code. Base64 is a conversion format commonly used to send binary attachments via email. It’s also a great way to hide malicious code. I’ve seen trojans use it before, but I’ve never seen it coded backwards.

Decoding this, we discovered the php code that has been affecting the RSS feed. We also found other bits that were monitoring cookies, collecting system information and other dangerous things like login information.

So how does this backwards code get executed? Well, the answer to that lies in the Akismet plugin directory. In a file named .akismet.cache_< date >.php, there was code with a strrev() function. This instructs the code in the database to reverse itself and become readable. It appears, although I can’t tell definitively without fully deconstructing the code, that this malware leverages the Akismet spam-filter plugin to do its dirty work. I’m sure the author took great pleasure in that.

Why is this only seen in things like Google Reader and My Yahoo? It turns out there’s a regular expression match done for key sites:

if(preg_match(“/bot|google|slurp|bing|msn|charlotte|crawl|yahoo|search|spider|inktomi|ask|alexa|seek/”,$_SERVER[“HTTP_USER_AGENT”])&&sizeof($_COOKIE)==0){

(Anwyn aside: In addition to the RSS readers, the Googlebot also sees the damaged code. Thus when I advance-googled for “aristocort” only on my site, Google turned up page after page that it said had that word–but if you clicked on a link, you got an entire category page where, of course, there was no mention of the spam words. Clever.)

Cleanup Procedure

If you’re seeing spam in your WordPress blog’s RSS feed and you have any dotfiles in your Akismet plugins directory (.akismet.cache.php, .akismet.cache_< date >.php, etc), then you’re probably suffering the same affliction as this blog. The fix:

1. Back up your WordPress files. This is just to be on the safe side.

2. Back up your WordPress Database. Again, just to be on the safe side.

3. [Disclaimer by Anwyn: We didn’t actually install Akismet on any other blog to double-check that the following affected files were not normally present in a healthy Akismet install. We just nuked them from orbit, and my blog and spam filter do not seem to be suffering. However, if you have more than one of these suspect files, you might want to search each of them for this string: strrev. This is the dangerous command and thus the dirty file. Daddyman googled for these kinds of files related to Akismet and found nothing normal–only warnings of spam exploitation–so you’re probably safe to delete them all, but we don’t know with 100 percent certainty.) Clean up WordPress by deleting any akismet dotfiles (.akismet.*) in the wp-content/plugins/akismet folder.

4. Clean up the database by removing all affected wp_options lines. The easiest way to do this is with phpmyadmin. Select your database, browse the wp_options table, and look for rows that have an option name of rss_< something >. Do not delete any of the following rows: rss_excerpt_length, rss_use_excerpt, rss_language. Delete any rows which have an option_name of rss_< long string of numbers and letters (hexadecimal) >. For example, in our installation an entry beginning with “rss_f541…” contained the base64_decode() string. You can delete any rows that have a name with a similar format, whether or not you see obviously malicious code; it will not harm your RSS.

5. Create a new post and verify that your RSS feed is now displaying correctly. Google Reader does a good job of refreshing on demand. The My Yahoo homepage doesn’t refresh promptly even if you select the refresh option, so you may need to wait a while before getting confirmation there.

6. Delete cookies in the browser(s) which you use to administer your site. This is just to be safe.

7. Change your WordPress password! You may also want to change your main database password. If you do that, be sure to also update it in wp-config.php.

8. Enjoy a spam-free, fully functional RSS service!

Staying Spam-Free

Here are two maintenance steps to help keep your blog clean and performing well:

1. Harden your WordPress installation! An ounce of prevention is worth a pound of cure.

2. Periodically purge spam comments from your database. When you classify a comment as spam, it disappears from sight, but the actual data remains in your database. In the case of this blog, which has been up for several years, 75 percent of the database (or about 9MB) was old spam comments. (Anwyn aside: Good Lord.) A simple sql command, run periodically, will remove all of that cruft and help optimize your database. The sql magic can be run either from phpMyAdmin or directly via the mysql CLI. Just connect to your database and execute the following statement:

delete from wp_comments where comment_approved=”spam”;

There are also some WordPress plugins, such as “Delete Spam Daily,” which profess to make this an even simpler process. I haven’t tried them, so be careful.

–Daddyman

(Anwyn aside: I hadn’t updated WordPress since it was first installed on this host, years ago. If I had, no doubt whatever back door the spammers came in through would have been eliminated.)

11 comments »

  1. Backward code, eh? Mighty clever. Apart from that, my knee jerk reaction is to be wary of any code calling “eval.” Is there any good reason to do that, as opposed to perverse ones like dressing up malicious code as harmless, non-executable data, and then turn around and executing that ostensibly non-executable data after all? I don’t know much about PHP; I’m assuming it does basically the same thing as its LISP counterpart, and hearkening back to my CS prof’s repeated warning that “EVAL is evil.” So perhaps I’m off base.

    Comment by Xrlq — July 14, 2009 @ 5:12 pm

  2. I’m sorry you have this problem and am very impressed that you solved it and shared the answer. I use TypePad and don’t think I have this problem, but what do I know? I’m not sure I have any readers.

    I’ve toyed with google and other readers but usually just surf the old fashioned way — through bookmarks.

    Comment by lifepundit — July 19, 2009 @ 4:17 pm

  3. FYI, there is a much simpler way to periodically purge spam comments: just check the “Automatically discard spam comments on posts older than a month” option under Akismet configuration.

    Comment by Xrlq — July 19, 2009 @ 8:50 pm

  4. Whoops. Guess I should have known that. :)

    Comment by Anwyn — July 19, 2009 @ 8:56 pm

  5. I just got hacked with this one too. The backwards code was in the wp-options table and the problem didn’t show up when viewed directly. A friend saw it in google reader. In my case, the actual code was in wp-content/plugins/podpress/optional_files/podpress_trac/.wp-cache.cache.php. Thanks for the help.

    Comment by Matt — August 19, 2009 @ 5:33 pm

  6. … and several other files under the plugins directory with names matching .*.cache.php. They were filled with random chars inside comment blocks to obfuscate the code.

    Comment by Matt — August 19, 2009 @ 6:35 pm

  7. Hey, Matt, I’m really glad this helped you–thanks for taking the time to say so. :)

    Comment by Anwyn — August 21, 2009 @ 10:04 am

  8. Just saw a couple of the same spams on Google Reader, this time on the comment RSS.

    Comment by Xrlq — August 23, 2009 @ 6:17 am

  9. Though oddly enough, that last comment of mine displayed properly in the same feed. Go figure.

    Comment by Xrlq — August 23, 2009 @ 10:04 am

  10. Thank you for posting this. Its what I was looking for

    Comment by Danni — August 13, 2011 @ 10:13 pm

  11. accidentaly googled to this site, excellent stuff

    Comment by James Reilly — August 24, 2011 @ 1:05 pm

Copy link for RSS feed for comments on this post or for TrackBack URI

Leave a comment

Line and paragraph breaks automatic, e-mail address never displayed, HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)




image: detail of installation by Bronwyn Lace