Any mod_rewrite gurus out there? (code, geekery, rant)
As an attempt at getting rid of some stupid spammers who are also trying to exploit nonexistent scripts on my site, I'm trying to redirect all requests that contain /../ in the original request URI (which are basically guaranteed to be an exploit attempt) elsewhere. However, it looks like mod_rewrite is only performing the substitution rule on the resolved path (i.e. it's treating /foo/../bar/ as /bar/) despite the fact that the REQUEST_URI environment variable still has the original /../-containing expression in it. I know my regexp is written correctly because the rule is working on other things (such as QUERY_STRING and HTTP_REFERER).
So, does anyone know if there's any configurations to mod_rewrite which might fix this behavior?
It's not a big deal but I've noticed a high correlation between the spammers who get through and the folks who are trying to find stupid CGI exploits and I figure anything that trips them up can only help.
Comments
RewriteRule . - [F]
Or something of the sort.
RewriteCond %{HTTP_REFERER} /\.\./ [OR]
RewriteCond %{REQUEST_URI} /\.\./ [OR]
RewriteCond %{QUERY_STRING} /\.\./
RewriteRule . http://google.com/ [R,L]
And here's what happens if I manually send a request to /blog/../env.cgi via telnet to port 80:
Trying 69.163.217.46...
Connected to beesbuzz.biz.
Escape character is '^]'.
GET /blog/../env.cgi HTTP/1.0
Host: beesbuzz.biz
HTTP/1.1 200 OK
Date: Thu, 17 Feb 2011 08:29:19 GMT
Server: Apache
MS-Author-Via: DAV
Vary: Accept-Encoding
Content-Length: 626
Connection: close
Content-Type: text/plain
SERVER_SIGNATURE=
UNIQUE_ID=TVzcX0WjzVcAAC9NGwAAAAAP
SERVER_PORT=80
HTTP_HOST=beesbuzz.biz
DOCUMENT_ROOT=/home/plaidfluff/beesbuzz.biz
SCRIPT_FILENAME=/home/plaidfluff/beesbuzz.biz/env.cgi
REQUEST_URI=/blog/../env.cgi
SCRIPT_NAME=/env.cgi
SCRIPT_URI=http://beesbuzz.biz/env.cgi
REMOTE_PORT=39394
[remainder omitted for brevity]
Note that the rewrite rule wasn't triggered, and env.cgi still shows a REQUEST_URI which should match it.
But if I falsify a referrer with the match string in it, it works:
Trying 69.163.217.46...
Connected to beesbuzz.biz.
Escape character is '^]'.
GET /blog/../env.cgi HTTP/1.0
Host: beesbuzz.biz
Referer: foo/../bar
HTTP/1.1 302 Found
Date: Thu, 17 Feb 2011 08:31:20 GMT
Server: Apache
Location: http://google.com/
Vary: Accept-Encoding
Content-Length: 202
Connection: close
Content-Type: text/html; charset=iso-8859-1
<DOCTYPE>
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href="http://google.com/">here</a>.</p>
</body></html>
And of course the QUERY_STRING one works fine too (although for whatever reason it's preserving the QUERY_STRING in the forwarded URL, which is a bit odd).