Configuring Apache to reject Shellshock attacks


This will be my first of many posts detailing how to configure a web server running the WordPress blogging software on Apache. Specifically, configuring the Apache web server or WordPress to reject (or make it possible after the fact to reject) attacks. I’m going to start with a simple attack that is easy to detect and reject: Shellshock.

Add the following to your .htaccess file:

# This protects against attempts to exploit the Bash execution bug. We're not
# susceptible to the attack but this makes it easy to spot the attack and
# blackhole the source.
RewriteCond %{QUERY_STRING} ^.*=\(\) [OR]
RewriteCond %{HTTP_REFERER} ^\(\)\s{ [OR]
RewriteCond %{HTTP_COOKIE} ^\(\)\s{ [OR]
RewriteCond %{HTTP_USER_AGENT} ^\(\)\s{
RewriteRule ^ blocked.php [NC,END,E=error-notes:shellshock-exploit]

The blocked.php file should be at the root level of your content. Generally the same directory that has your wp-login.php file. The contents are below. Note that the most important aspect is setting the HTTP response code to 400. This makes it easy to recognize these types of attacks when scanning the Apache access.log (or wherever your web server records client requests) and provides feedback to humans about why their request was rejected.

<?php http_response_code(400) ?>
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
    <head>
        <title>400 Bad Request</title>
    </head>
    <body>
<?php if ($_SERVER['REDIRECT_error-notes'] == "wp-account-registration") { ?>
        <h1>WordPress account registration is disabled</h1>

        <p>If you're trying to register a WordPress account please email
        <?php print($_SERVER['SERVER_ADMIN']) ?>
        with the user name you would like to use and I'll set it up manually.
        My apologies for the hassle but the volume of attempts by malware to
        register bogus accounts necessitates this action.
        </p>
<?php } else { ?>
        <h1>The HTTP request looks like an attack</h1>

        <p>The HTTP request appears to be an attack on my web server for reason
        "<?php print($_SERVER['REDIRECT_error-notes']) ?>".

        Your computer IP address (
        <?php print($_SERVER['REMOTE_ADDR']) ?>
        ) has been blacklisted.
        </p>

        <p>You can email
        <?php print($_SERVER['SERVER_ADMIN']) ?>
        to have your IP address removed from the blacklist if you believe
        the blacklisting is in error if you have removed the malware from
        your computer or believe my firewall has made a mistake in
        blacklisting your computer.
<?php } ?>
<?php
apache_setenv('error-notes', $_SERVER['REDIRECT_error-notes']);
if ($_SERVER['REMOTE_ADDR'] == '127.0.0.1' || $_SERVER['REMOTE_ADDR'] == '::1') {
    print("<table><tr><th>\$_SERVER</th><th>Value</th></tr>\n");
    foreach ( $_SERVER as $key => $value )
    {
        print("<tr><td>" . $key . "</td><td>" . $value . "</td></tr>\n");
    }
    print("</table>\n");
    print("<table><tr><th>\$_REQUEST</th><th>Value</th></tr>\n");
    foreach ( $_REQUEST as $key => $value )
    {
        print("<tr><td>" . $key . "</td><td>" . $value . "</td></tr>\n");
    }
    print("</table>\n");
    print("<table><tr><th>\$_ENV</th><th>Value</th></tr>\n");
    foreach ( $_ENV as $key => $value )
    {
        print("<tr><td>" . $key . "</td><td>" . $value . "</td></tr>\n");
    }
    print("</table>\n");
}
?>
    </body>
</html>

Update 2015-05-16: The original title of this article was “Configuring WordPress…” hence the URI to this article. With the recent uptick in views of this article I decided to correct that mistake.