24th July, 2007

ModSecurity Fun and Protection

Tuesday, 11:12 am in CodeGirl

I’ve been watching in horror ever since I implemented Apache error pages that email me errors at the sheer unadulterated weight of PHP injection attempts that my site has been getting.  I noted that they all seemed to be failing with a status code of 403, but in my curiosity I decided to see if I could re-write some .htaccess rules to throw different errors so that I wasn’t getting emailed every time.  The email/database logging system was set up really to notify me of 404 errors, so once the initial curiosity subsided I wasn’t all that interested to know the details of every single phpFanBase protection.php hack attempt (I get about six a day, if you’re curious).

However, no matter what I put into my .htaccess, I couldn’t stop the server throwing 403s.  Hrm.  Some further investigation later, and I chanced upon the realisation that my host must be using an implimentation of the awesome ModSecurity Apache module.  This made things much easier!

Now I knew what I was really trying to do was get ModSecurity to throw an error code that wasn’t 403, which is all of one line.  While I was at it I also noticed that it wasn’t picking up a couple of the common attempted exploits that were being thrown at my site; these were instead dying on a 404.  So I wrote the following little block of code to put into my .htaccess:

## ModSecurity
<IfModule mod_security.c>
  # turn ModSecurity on
  SecFilterEngine On
  
  # set up rejection to throw a 501
  SecFilterDefaultAction "deny,log,status:501"
  
  # some rules for common attacks that aren't covered by generic ModSecurity
  SecFilterSelective REQUEST_URI "\.php\?.*=(https?|ftp)\:/.*"
  SecFilterSelective REQUEST_URI "protection\.php\?action=logout&siteurl="
</IfModule>

Why throw a 501 error?  I admit it was kind of arbitrary.  Like I said, I didn’t want to use 403 since I get notices on those.  I considered 410, but I use 410s ‘legitimately’ to indicate files that have been permanently deleted from the server.1  I considered a 406 Not Acceptable, mostly because of the name, but rejected that since 4xx errors are reserved for client issues, and I wanted to make a statement that it’s the server that’s explicitly been configured to deny these requests.  So in the end I settled on 501 Not Implemented:

The server does not support the functionality required to fulfill the request. This is the appropriate response when the server does not recognize the request method and is not capable of supporting it for any resource.

I reckon saying that my server “does not support the functionality” of a remote PHP injection attempt was pretty well exactly what I was after (even if maybe it’s not strictly W3C).

The next two SecFilterSelective lines are me trying to set up some specific filters to prevent against common exploits I get here at void-star.net.  The first denies anything that looks like an attempt to exploit index.php?x=file.inc style templates.  Which I don’t actually use, but still get attempted exploits for.  The second line explicitly rejects phishing for phpFanBase hack attempts.

So, there you go.

  1. As should you, incidentally.  404 errors are only for temporary file removals.  Files and directories that require 410 errors need to be explicitly stated in your .htaccess file, the easiest way is using Redirect 410 /path/to/dead.file.  For sites and files that have been moved, you should use Redirect 301 /old.file http://newsite.com/new.file.  Google will love you for it. ^

Comments

Add Comment
auto insert line breaks
use log.code
use smilies
Verification
  • v-s.net v0.6 and all content (unless noted) © Dee.
  • sk.log v0.6 spat this out in 2.045 seconds.
  • 18 / 216,403
artistic-twobyfour