How to write a WAF rule - Modsecurity Rule Writing

The ModSecurity Reference Manual should be used in all cases where questions arise over the syntax of commands: “https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual”.

In terms of rule writing the main directive to know is SecRule, which is used to create rules and thus does most of the work.

Every rule defined by SecRule conforms to the same format, as below:

SecRule VARIABLES OPERATOR [ACTIONS]

The three parts have the following meanings:

  1. The VARIABLES specify which places to check in an HTTP transaction. Examples of variables include ARGS (all arguments including the POST Payload), REQUEST_METHOD (request method used in the transaction), REQUEST_HEADERS (can be used as either a collection of all of the request headers or can be used to inspect selected headers) etc.

The full list of variables is available under https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#Variables.

 

  1. The OPERATOR specifies a regular expression, pattern or keyword to be checked in the variable(s). Operators begin with the @ character.

 

The full list is of operators is available under https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#Operators.

 

  1. The ACTIONS specify what to do if the rule matches. Actions are defined into seven categories Disruptive (used to allow ModSecurity take an action e.g. allow, block etc), Flow (affect the flow e.g. skip), Meta-data (used to provide more information about rules), Variable (used to set, change and remove variables), Logging (used to influence the way logging takes place) and Special (used to provide access to another class of functionality) and Miscellaneous (contain actions that don’t belong in any of the other groups) actions. If no ACTIONS are provided, default actions apply as per SecDefaultAction (phase:2,log,auditlog,pass).

 

The full list of actions is available under https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#Actions.

 

 

 

Rule Syntax

Simple rules and operators

The following rule looks at the rquest URI trying to match the regular expression pattern <script> against it. The double quotes are used as the second parameter contains a space.

SecRule REQUEST_URI “@rx <script>”

To split a long line into two, use a single backslash character followed by a newline:

SecRule ARGS KEYWORD \

     phase:1,t:none,block

Multiple variables can be used in a rule as long as they are separated using the pipe character, for example:

SecRule REQUEST_URI|REQUEST_PROTOCOL <script>

The SecDefaultAction directive is used in the case where no actions are defined for a rule. So the following rule:

SecRule ARGS D1

Is equivalent to:

SecRule ARGS D1 phase2:log:auditlog,pass

 

Rule Example 1 – XSS attack

The following rule is used to avoid XSS attacks by checking for a <script> pattern in the request parameters and header and generates and ‘XSS Attack’ message with a 404 status response.

SecRule ARGS|REQUEST_HEADERS “@rx <script>” id:101,msg: ‘XSS Attack’,severity:ERROR,deny,status:404

VARIABLES

ARGS – Request Parameters

REQUEST_HEADERS – All of the request headers

OPERATOR

“@rx <script>” – Performs a regular expression match of the pattern (in this case <script>) provided as parameter

ACTIONS

id, msg, severity, deny, status – These are all of the actions to be performed if the pattern is matched

id:101 – The unique id that is assigned to this rule (or chain) in which it appears.

msg:”XSS Attack” – The custom message (i.e. XSS Attack) assigned to the rule (or chain) in which it appears.

Severity:ERROR – The severity of the rule. Severities include EMERGENCY (0), ALERT (1), CRITICAL (2), ERROR (3), WARNING (4), NOTICE (5), INFO (6) and DEBUG (7).

deny – This stops rule processing and intercepts transaction. This is a disruptive action.

status:404 – This specifies the response status code (404) with actions deny and redirect.

 

Rule Example 2 – Whitelist IP Address

The following example shows how to whitelist an IP Address to bypass the ModSecurity engine:

SecRule REMOTE_ADDR “@ipMatch 192.168.1.101” \

id:102,phase:1,t:none,nolog,pass,ctl:ruleEngine=off

VARIABLES

REMOTE_ADDR – The IP address of the remote client.

OPERATOR

“@ipMatch 192.168.1.101” – Performs an IPv4 or IPv6 match of the REMOTE_ADDR variable data, in this case this is the whitelisted IP address.

ACTIONS

id:101 – The unique id that is assigned to this rule (or chain) in which it appears.

phase:1 – Places the rule (or chain) in Phase 1 processing. There are 5 phases including Request Headers (1), Request Body (2), Response Headers (3), Response Body (4) and Logging (5).

t:none – Indicates that no action is used to transform the value of the variable used in the rule before matching. For example t:utf8toUnicode converts all UTF-8 character sequences to Unicode to assist in input normalization.

nolog – Prevents rule matches from appearing in both the error and audit logs.

pass – Continues processing with the next rule in spite of a successful match.

ctl:ruleEngine=off – This action changes ModSecurity configuration on transient, per-transaction basis. This will affect only the transaction in which the action is executed. In this case, the ModSecurity rule engine is turned off.

 

Rule Example 3 – Chaining rules

The following section shows an example of chaining two rules. In this case, the first rule checks the username (ARGS:username) for the string admin (streq admin) using a string comparison. If the first rule holds true, the second rule is activated which denies all requests that are not from the REMOTE_ADDR 192.168.1.111 IP Address (!streq 192.168.1.111).

SecRule ARGS:username “@streq admin” chain,deny

SecRule REMOTE_ADDR “!streq 192.168.1.111”

 

Rule Example 4 – Shellshock Bash Attack

The following section shows an example of the rules required to mitigate the Shellshock Bash attack. There are two rules required in this case as detailed below.

SecRule REQUEST_LINE|REQUEST_HEADERS|REQUEST_HEADERS_NAMES "@contains () {" "phase:1,id:'2100080',block,t:none,t:utf8toUnicode,t:urlDecodeUni,t:compressWhitespace,msg:'SLR: Bash ENV Variable Injection Attack',tag:'CVE-2014-6271',tag:'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-6271',tag:'https://securityblog.redhat.com/2014/09/24/bash-specially-crafted-environment-variables-code-injection-attack/'"

 

VARIABLES

REQUEST_LINE – This variable holds the complete request line sent to the server (including the request method and HTTP version information).

REQUEST_HEADERS – All of the request headers.

REQUEST_HEADERS_NAMES – All of the names of the request headers.

OPERATOR

"@contains () {" – Checks the REQUEST_LINE|REQUEST_HEADERS|REQUEST_HEADERS_NAMES variables for the string ‘() {’ and returns true if found.

ACTIONS

phase:1 – Places the rule (or chain) in Phase 1 processing. There are 5 phases including Request Headers (1), Request Body (2), Response Headers (3), Response Body (4) and Logging (5).

id:'2100080' – The unique id that is assigned to this rule (or chain) in which it appears.

block – This performs the disruptive action defined by the previous SecDefaultAction. This allows rule writers to request a blocking action, but withouth specifying how the blocking is to be done. The SecRuleUpdateActionById directive allows you to override how a rule handles blocking. Please refer to Appendix B for further details.

t:none – Indicates that no action is used to transform the value of the variable used in the rule before matching.

t:utf8toUnicode – Converts all UTF-8 character sequences to Unicode to assist in input normalization.

t:urlDecodeUni – Decodes a URL-encoded input string with support for the Microsoft-specific %u encoding.

t:compressWhitespace – Converts any of the whitespace characters (0x20, \f, \t, \n, \r, \v, 0xa0) to spaces (ASCII 0x20) compressing multiple consecutive space characters into one.

msg:'SLR: Bash ENV Variable Injection Attack',tag:'CVE-2014-6271' – The custom message (i.e. XSS Attack) assigned to the rule (or chain) in which it appears.

tag:'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-6271'

tag:'https://securityblog.redhat.com/2014/09/24/bash-specially-crafted-environment-variables-code-injection-attack/' – Assigns a tag (category) to a rule (or chain). This is metadata to allow easy automated categorization of events. Multiple tags can be specified on the same rule.

 

SecRule REQUEST_BODY "@contains () {" "phase:2,id:'2100081',block,t:none,t:utf8toUnicode,t:urlDecodeUni,t:compressWhitespace,msg:'SLR: Bash ENV Variable Injection Attack',tag:'CVE-2014-6271',tag:'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-6271',tag:'https://securityblog.redhat.com/2014/09/24/bash-specially-crafted-environment-variables-code-injection-attack/'"

 

VARIABLES

REQUEST_BODY – All of the request body.

OPERATOR

"@contains () {" – Checks the REQUEST_BODY variable for the string ‘() {’ and returns true if found.

ACTIONS

phase:2 – Places the rule (or chain) in Phase 2 processing. There are 5 phases including Request Headers (1), Request Body (2), Response Headers (3), Response Body (4) and Logging (5).

id:'2100081' – The unique id that is assigned to this rule (or chain) in which it appears.

block – This performs the disruptive action defined by the previous SecDefaultAction. This allows rule writers to request a blocking action, but withouth specifying how the blocking is to be done. The SecRuleUpdateActionById directive allows you to override how a rule handles blocking. Please refer to Appendix B for further details.

t:none – Indicates that no action is used to transform the value of the variable used in the rule before matching.

t:utf8toUnicode – Converts all UTF-8 character sequences to Unicode to assist in input normalization.

t:urlDecodeUni – Decodes a URL-encoded input string with support for the Microsoft-specific %u encoding.

t:compressWhitespace – Converts any of the whitespace characters (0x20, \f, \t, \n, \r, \v, 0xa0) to spaces (ASCII 0x20) compressing multiple consecutive space characters into one.

msg:'SLR: Bash ENV Variable Injection Attack',tag:'CVE-2014-6271' – The custom message (i.e. XSS Attack) assigned to the rule (or chain) in which it appears.

tag:'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-6271'

tag:'https://securityblog.redhat.com/2014/09/24/bash-specially-crafted-environment-variables-code-injection-attack/' – Assigns a tag (category) to a rule (or chain). This is metadata to allow easy automated categorization of events. Multiple tags can be specified on the same rule.

 

Appendix A – KEMP WUI Settings

The KEMP WUI allows the customer to select the default operation as ‘Audit Only’ or ‘Block Mode’ as shown in Figure 1 below.

The Audit Only mode of operation sets the SecDefaultAction to phase:2,log,auditlog,pass.

The Block Mode of operation sets the SecDefaultAction to phase:2,log,auditlog,block,drop.

Appendix B – Rule Block Function

The rule block function is quite a complicated and deserving of further explanation. The following example is taken from https://github.com/Spiderlabs/ModSecurity/wiki/Reference-Manual#block and further explanatory text has been added.

The block action is essentially a placeholder that is intended to be used by rule writes to request a blocking action, but without specifying how the blocking is to be done. The specification of how the blocking is to be done is decided using the SecDefaultAction command. The block action is a placeholder that will just be replaced by the action from the last SecDefaultAction in the same context.

Block Example 1

The following example shows the SecDefaultAction set to deny. The second rule will “deny” because the SecDefaultAction is set to deny.

SecDefaultAction phase:2,deny,id:101,status:403,log,auditlog

SecRule ARGS attack2 phase:2,pass,id:103

SecRule ARGS attack1 phase:2,block,id:102

Block Example 2

The following example shows the usage of the SecRuleUpdateActionById command to override how a rule handles blocking. The SecRuleUpdateActionById command allows a rule to be reverted back to the previous SecDefaultAction. In this example, the first rule (SecRule ARGS attack1 phase:2,deny,id:1) would deny based on meeting the successful conditions associated with the rule.

By using the SecRuleUpdateActionById against rule Id 1 and indicating block, we are associating the first rule action to that of the SecDefaultAction which is pass. So in the case, the first rule would pass based on meeting the successful conditions associated with the rule; it would not deny.

SecDefaultAction phase:2,pass,log,auditlog

SecRule ARGS attack1 phase:2,deny,id:1

SecRuleUpdateActionById 1 block

 

Was this article helpful?

0 out of 0 found this helpful

Comments