1

I want to create a mod security2x rule that will block the GET request to a specific URL.

for example I want to block the URL with the GET in the header: 'www.test.com'

I've never made a rule within modsecurity, and not sure this will work with anomaly detection mode.

This would be an example of the GET request: GET/secure/bla/test/etc/

This is what I have so far: SecRule ARGS "www.test.com" phase:2,log,deny,id:'1234',msg:'403 Access Denied'

Chris Hawkins
  • 55
  • 1
  • 6

2 Answers2

2

You want something like this:

SecRule REQUEST_URI "@streq /secure/bla/test/etc/" \
     "phase:1,id:1234,t:none,t:urlDecode,t:lowercase,t:normalizePath,deny,status:403,msg:'403 Access Denied',chain"
    SecRule REQUEST_METHOD "@streq get" "t:none,t:lowercase"

You need to chain two rules together as you want to check two conditions (path is /secure/bla/test/etc/ and method is GET).

If you want to add a third rule to check the host (e.g. if you have multiple virtual hosts and this URL is valid for GET requests on some of them), then you can:

SecRule REQUEST_URI "@streq /secure/bla/test/etc/" \
     "phase:1,id:1234,t:none,t:urlDecode,t:lowercase,t:normalizePath,deny,status:403,msg:'403 Access Denied',chain"
    SecRule REQUEST_METHOD "@streq get" "t:none,t:lowercase,chain"
         SecRule SERVER_NAME "@streq www.example.com"

Or alternatively you can use REQUEST_URI_RAW which will include the protocol and hostname as well as the resource requested:

SecRule REQUEST_URI_RAW "^https?://www.test.com/secure/bla/test/etc/" \
     "phase:1,id:1234,t:none,t:urlDecode,t:lowercase,t:normalizePath,deny,status:403,msg:'403 Access Denied',chain"
    SecRule REQUEST_METHOD "@streq get" "t:none,t:lowercase" 

You'll notice I've also added quite a few transformation functions (the t: bits) to help avoid people trying to get around this rule (e.g. with a path like /secure/bla/TEST/../test/etc/).

All of this is covered in the reference manual: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual but does take a bit of practice to get used to I'll admit!

Anomaly detection mode simple means rules that might fire for valid requests do not blocked immediately but instead, assigned a score and if the total score of all the rules for that request is above a certain threshold then it blocks, if not it doesn't. This allows for "noisy" rules to still be included but to be ignored unless lots of noisy rules all fire for a request, or if one important rule is fired.

There is nothing to stop you explicitly blocking with the "deny" option as I have done above - even in anomaly detection mode. This rule seems fairly safe from ever firing accidentally for a legitimate request (once you have tested it works!) so I would just go from straight blocking as I have done above. The alternative is to replace deny with block,setvar:tx.anomaly_score=+%{tx.critical_anomaly_score} which will have the same effect when the score is checked later but in my mind needlessly complicates the readability of the rule since it will always block anyway.

Anomaly scoring versus traditional scoring is covered in more detail in this blog post: http://blog.modsecurity.org/2010/11/advanced-topic-of-the-week-traditional-vs-anomaly-scoring-detection-modes.html

Barry Pollard
  • 40,655
  • 7
  • 76
  • 92
  • Thank you! I have just one more question, so I have now altered the string you added above. Do – Chris Hawkins Oct 11 '16 at 19:49
  • Do I need to need to add this whole string? "GET /secure/bla/test/etc/=www.test.com" – Chris Hawkins Oct 11 '16 at 19:51
  • SecRule REQUEST_URI "@streq /secure/bla/test/etc/=www.test.com" \ "phase:1,id:1234,t:none,t:urlDecode,t:lowercase,t:normalizePath,deny,status:403,msg:'403 Access Denied,chain'" SecRule REQUEST_METHOD "@streq get" "t:none,t:lowercase" – Chris Hawkins Oct 11 '16 at 19:52
  • That doesn't make sense. The REQUEST_URI contains the full path requested (i.e. /secure/bla/test/etc). It does not contain the hostname. And certainly not in that weird "path=hostname" syntax - where did you get that from? The REQUEST_URI_RAW contains the protocol, host and and path (e.g. `http://www.example.com/secure/bla/test/` etc) as I showed in my second example above. Alternatively you could add a 3rd rule (also chained) to check out the SERVER_NAME variable. Have edited my answer to include that option too. – Barry Pollard Oct 11 '16 at 20:00
  • I understand now, although I keep getting "ModSecurity: No action id present within the rule" I changed the rule id to any other number and its still not working – Chris Hawkins Oct 13 '16 at 17:54
  • SecRule REQUEST_URI "@streq \/secure\/test\/bla\/bla\?.+" \ "phase:1,id:19,t:none,t:urlDecode,t:lowercase,t:normalizePath,deny,status:403,msg:'403 Access Denied,chain'" SecRule REQUEST_METHOD "@streq get" "t:none,t:lowercase" I keep getting the No action id present within rule – Chris Hawkins Oct 13 '16 at 18:02
  • Just noticed a typo in my rules which I've corrected now. The msg close quote was after the chain action (msg:'403...,chain') instead of before it (msg:'403...',chain). So it wasn't seeing these as chained rules so demands a mandatory id in the following separate rules. Once you properly add the chain action in it will see them as one long rule and you will no longer get that error message. – Barry Pollard Oct 13 '16 at 18:03
  • The rule doesnt seem to be working for me, if I switched the SecRule would this be correct? – Chris Hawkins Oct 13 '16 at 19:34
  • 'SecRule REQUEST_METHOD "@streq get" "t:none,t:lowercase,chain" SecRule REQUEST_URI "@streq \/secure\/ajax\/SecureAjaxModel\/setSSOCredentials\?.+" \ "phase:1,id:98,t:none,t:urlDecode,t:lowercase,t:normalizePath,deny,status:403,msg:'403 Access Denied'"' – Chris Hawkins Oct 13 '16 at 19:34
  • Shouldn't matter either way. Though you can only put certain actions (id,deny,status,msg) in the first rule of a chain. I suggest you just run just one rule, test whether that works (perhaps temporarily replacing `deny` with `log` and checking the ModSecurity logs) and then repeat with the second rule. Then try again with them chained. Or turn on debug logging (warning this logs a LOT of data) and use that to try to figure out why it's not working. – Barry Pollard Oct 13 '16 at 19:47
  • I just want to say thank you, I was wondering. If I use it in anomaly mode the code will become this : `SecRule REQUEST_URI "@streq /secure/bla/test/etc/" \ "phase:1,id:1234,t:none,t:urlDecode,t:lowercase,t:normalizePath,block,setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},status:403,msg:'403 Access Denied',chain" SecRule REQUEST_METHOD "@streq get" "t:none,t:lowercase"` where in 'block,setvar:tx.anomaly_score=+%{tx.critical_anomaly_score}' can I add the score I want? I am using 5 in the 49/58 inbound and outbound rules – Chris Hawkins Oct 13 '16 at 21:59
  • Yes you can do that. However the setting of the variable should be done in the last rule of the chain as, confusingly, it's actioned as soon as that part of the chained rule matches. See here for more details: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#setvar and in particular the bit in bold. As I said in my original answer if you are definitely going to block on this I'm not sure the value in waiting for the anomaly score to be checked later - just block it straight away with deny. But if you want to keep all the blocking in one place then you can do it as you suggest. – Barry Pollard Oct 13 '16 at 22:12
  • `SecRule REQUEST_URI "@streq /secure/bla/test/etc/" \ "chain,phase:1,id:1234,t:none,t:urlDecode,t:lowercase,t:normalizeP‌​ath,block,status:403,msg:'‌​403 Access Denied'" SecRule REQUEST_METHOD "@streq get" "t:none,t:lowercase,setvar:tx.‌​anomaly_score=+%{tx.‌​critical_anomaly_sco‌​re}"` I understand, then I can add setvar:tx.anomaly_score=5. Another question, in the request_URI do I need to make this a regular expression? – Chris Hawkins Oct 13 '16 at 22:27
  • By default it's a regular expression. When you use @streq that changes to a straight string comparison. But while I'm trying to help here, Stack Overflow isn't intended as a teaching site to teach you a whole programming language, but more as a question and answer site to specific problems. I highly recommend you purchase the ModSecurity Handbook (https://www.feistyduck.com/books/modsecurity-handbook/) written by the original author of ModSecurity. Quite cheap and, although it's a little old now and doesn't cover the more recent versions, it's still the best book for learning ModSecurity. – Barry Pollard Oct 13 '16 at 23:01
  • I've been reading and I wanted to confirm, the rule above needs to ALLOW POST, and BLOCK GET on this path /secure/test/bla/bla – Chris Hawkins Oct 14 '16 at 14:06
  • Yes that is what it will do. If all the rules in the chain do not match then the disruptive actions in the first rule (i.e. the deny) will not be fired. It's a bit confusing as disruptive actions have to be specified in first rule but are only actioned if all rules in chain pass. The author has said if he was starting again he'd have written ModSecurity to force disruptive actions to be placed in last rule of chain, but that's the way it is. Also non-disruptive actions (i.e. setting variables) happen when that part of the chain matches. Which is why they need to be on last rule on chain. – Barry Pollard Oct 14 '16 at 15:31
0

I would have used a whitelist approach to block the GET request,for example, login.php and change_password.php doesn't require any GET request.

    SecRule REQUEST_URI|ARGS_NAMES|REQUEST_FILENAME "/secure/bla/test/etc/" "phase:2,t:none,deny,chain"
    SecRule REQUEST_FILENAME "@pm login.php change_password.php"
Alvin567
  • 305
  • 2
  • 8