3

One of my servers was attacked by DDoS a couple of days ago and it lasted for 4 days. Below are the logs snippet of the request:

36.224.180.253 - - [14/May/2013:03:11:46 +0800] "GET //?f5b2fd2f860dc=9597624054932145 HTTP/1.1" 301 178 "-" "Opera/9.80 (Windows NT 6.1; WOW64) Presto/2.12.388 Version/12.14"
36.224.180.253 - - [14/May/2013:03:11:50 +0800] "GET //?d69e553a2e8cc=8383534686131949 HTTP/1.1" 301 178 "-" "Opera/9.80 (Windows NT 6.1; WOW64) Presto/2.12.388 Version/12.14"
36.224.180.253 - - [14/May/2013:03:11:53 +0800] "GET //?cd28bceecb2f7=8014028628342069 HTTP/1.1" 301 178 "-" "Opera/9.80 (Windows NT 6.1; WOW64) Presto/2.12.388 Version/12.14"
36.224.180.253 - - [14/May/2013:03:11:59 +0800] "GET //?e39ba4d777ca3=8890936876339672 HTTP/1.1" 301 178 "-" "Opera/9.80 (Windows NT 6.1; WOW64) Presto/2.12.388 Version/12.14"
36.224.180.253 - - [14/May/2013:03:12:02 +0800] "GET //?3bc0dd265e14b=2334116190596257 HTTP/1.1" 301 178 "-" "Opera/9.80 (Windows NT 6.1; WOW64) Presto/2.12.388 Version/12.14"
36.224.180.253 - - [14/May/2013:03:12:06 +0800] "GET //?8b645989c8334=5444999657995141 HTTP/1.1" 301 178 "-" "Opera/9.80 (Windows NT 6.1; WOW64) Presto/2.12.388 Version/12.14"
36.224.180.253 - - [14/May/2013:03:12:09 +0800] "GET //?bb1f56833c451=7309469290160174 HTTP/1.1" 301 178 "-" "Opera/9.80 (Windows NT 6.1; WOW64) Presto/2.12.388 Version/12.14"
36.224.180.253 - - [14/May/2013:03:12:11 +0800] "GET //?5fb9da415957e=3739296350043726 HTTP/1.1" 301 178 "-" "Opera/9.80 (Windows NT 6.1; WOW64) Presto/2.12.388 Version/12.14"

Nevermind the IP, it's just one of the massive requests. There are more than 3000+ different IPs using the same GET requests pattern.

I'm using Nginx (nginx-1.2.8-1.el6.ngx.x86_64) behind Varnish (varnish-3.0.3-1.el6.x86_64).

My question is, how to redirect this kind of request to specific page, say 404.html?

Danack
  • 1,216
  • 1
  • 16
  • 27
chr1x2
  • 39
  • 1
  • 5

1 Answers1

2

Rewrite in Nginx only works on paths, so you need to use a compare on the variables separately to identify them. What you asked for would look like:

if ($args ~ "([a-f0-9]{12,})=([a-f0-9]{12,})" ){
    rewrite ^/$ /404_rewrite?;
}

location  /404_rewrite {
    return 404;
}
  • The matching for the args has to be inside quotes as otherwise the { and } would confuse Nginx.

  • The ? at the end of the rewrite makes Nginx drop all the parameters, rather than append them to the rewritten url.

However you may wish for Nginx to try and delay each request in the DOS, rather than handle them as quickly as possible.

limit_req_zone  $binary_remote_addr  zone=dos_attack:20m   rate=30r/m;

if ($args ~ "([a-f0-9]{12,})=([a-f0-9]{12,})" ){
    rewrite ^/$ /404_rewrite?;
}

location  /404_rewrite {
    limit_req   zone=dos_attack  burst=1;
    internal;
    return 404;
}

What this does is:

  • Set the number of requests at 30r/m which is 30 requests per minute or one request every two seconds.

  • Sets the burst at 1. For normal rate limiting the burst is set at >1 to allow clients to not be limited if they accidentally go over the rate limit for a short period of time.

  • Allocates 20 megabytes to store the information about the rate limiting zone. According to the rate limit documentation each $binary_remote_addr takes 64 bytes to store, so this rate limiting would work up to a couple of hundred thousand individual machines doing the DOS. If it was more machines than that, the rate limiting would break down.

Danack
  • 1,216
  • 1
  • 16
  • 27
  • 1
    You can also use [`return 444`](http://wiki.nginx.org/HttpRewriteModule#return) to have nginx drop the connection without sending a response. – mgorven May 16 '13 at 23:43
  • @Danack You're a genius! That's what I'm looking for and very well explained. Thank you very much! – chr1x2 May 17 '13 at 05:30
  • @mgorven Thanks for the input. Drop instead of response, that makes sense. – chr1x2 May 17 '13 at 05:32
  • hmm... this argument is also redirecting to 444. "GET /?publicationSubCategoryId=666&update=13687711666281298" – chr1x2 May 17 '13 at 06:22
  • I updated it to only match hexadecimals but you will need to understand what the regex is doing and make sure it's not going to pickup legitimate requests. – Danack May 17 '13 at 06:41
  • @Danack Am I correct? `(\x{12,})=(\x{12,})` the 12 means equals and/or over 12 characters matches this args? – chr1x2 May 18 '13 at 03:59
  • Yes the syntax {a,b} means at least 'a' count, at most 'b' counts. If you leave b out it becomes between 'a' and infinity. Btw I removed the \x as it wasn't working properly, changed to a standard character class [a-f0-9] – Danack May 18 '13 at 11:54