1

I'm trying to setup a RewriteRule for Apache 2.4 that allows me to return a 403 code when any keywords are found in the QUERY_STRING.

I'm trying to return 403 whenever anyone does some malicious attacks such as:

wget /etc/passwd
or wp-login

in the QUERY_STRING.

Here are a few generic examples Im trying to block:

"GET /wp-login.php HTTP/1.1"
"GET /setup.cgi?next_file=somefile HTTP/1.1"
"GET //public/html HTTP/1.1"
"GET /wget+http://192.168.1.1:8080/etc/passwd HTTP/1.1"
"POST /admin/Login.php?user=joe&passwd=77 HTTP/1.1"
"POST /httpdir/wp-login.php?user=bob&pw=12345 HTTP/1.1"

I have no idea why it does not appear to be working. I've tried several things to get it to work with no luck so far which is why I am posting. I'm sure its something subtle or easy.

RewriteCond %{QUERY_STRING} ^/.*(wget|/etc|admin|wp-login|setup|public).*$
RewriteRule .* - [F,NC]

[UPDATE] I added several specific examples and added the POST conditions I would like to catch as well. Thank you so much for your help!

Tim
  • 203
  • 1
  • 9

1 Answers1

0
RewriteCond %{QUERY_STRING} ^/.*(wget|/etc|admin|wp-login).*$
RewriteRule .* - [F,NC]

The forward slash at the start of the CondPattern, ie. ^/.* is a literal slash at the start of the query string, so this is unlikely to match the type of URL you are trying to block.

If you just want to match any one of a series of keywords anywhere in the query string then you don't need the start-of-string and end-of-string anchors or the encompassing match-everything .* patterns at either end of the regex.

Try the following instead:

RewriteCond %{QUERY_STRING} (wget|/etc|admin|wp-login) [NC]
RewriteRule ^ - [F]

You probably do want the NC flag on the RewriteCond directive to make the query string match case-insensitive, but the NC flag on the RewriteRule is superfluous.

You can also optimize the RewriteRule pattern by simply asserting the start-of-string (ie. ^), rather than matching everything (which unnecessarily forces traversal of the URL-path). You only need the RewriteRule to be successful - you aren't trying to match anything here.

Also, the order of these directives does matter. Any blocking directive should be before any existing mod_rewrite directives.

UPDATE: If you want to match whole words only and not partial matches. eg. To avoid matching "administrator" and "wowgetter", etc. then include word boundaries on the regex. eg. \b(wget|/etc|admin|wp-login)\b.

MrWhite
  • 12,647
  • 4
  • 29
  • 41
  • Updated answer with alternative regex to match _whole words_ only, avoiding partial matches. – MrWhite Mar 24 '20 at 17:15
  • I think Im missing something. If I telnet 80 and type: GET /admin HTTP/1.1 it fails to catch it, but if I type: GET /admin alone it works. It seems that I missing how the ending HTTP/1.1 works with this rule? How do I make that work? That seems to be my main issue. – Tim Mar 28 '20 at 17:54
  • "GET /admin alone it works" - But that shouldn't "work" either!? You stated in your question that you wanted to trap these keywords in the _query-string_ portion of the URL - that's what the rule above does. A request of the form `GET /admin` does not contain a query string - it contains a URL-path only. (?) Please edit your question to include examples of the full URL you are wanting to block. – MrWhite Mar 28 '20 at 18:06