Rule Exclusion Script on Steroids


The ModSecurity / OWASP Core Rule Set tutorials here at netnea.com are visited by over 8,000 times a month. With many of the unique visitors, the auxiliary script modsec-rulereport.rb is a favorite. The tool allows you to generate rule exclusions based on a ModSecurity rule alert message.

Today, I’m presenting you a new version of the script. A complete rewrite. The new version has the following features:

  • It supports the four canonical types of rule exclusions by id and by tag
  • Calling the rule exclusion types is now consistent (and it really was not before)
  • Optional persistence of rule IDs
  • Special CRS rules that reference variables or administrative rules that should not be
    excluded are treated specially (instead of a rule exclusion, there is an advisory text)
  • Optional addition of meta information to comments of the rule exclusion
  • JSON output
  • Support for full variety of ModSecurity rule alerts (also for exotic operators)

Here are a few examples

Alert 1:

[2021-06-03 22:54:45.858724] [-:error] - - [client 127.0.0.1] ModSecurity: Warning. Pattern match "(?i:(?:(?:s(?:t(?:d(?:dev(_pop|_samp)?)?|r(?:_to_date|cmp))|u(?:b(?:str(?:ing(_index)?)?|(?:dat|tim)e)|m)|e(?:c(?:_to_time|ond)|ssion_user)|ys(?:tem_user|date)|ha(1|2)?|oundex|chema|ig?n|pace|qrt)|i(?:s(null|_(free_lock|ipv4_compat|ipv4_mapped|ipv4|ipv ..." at ARGS:keys. [file "/apache/conf/owasp-modsecurity-crs-3.0.0-rc1/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf"] [line "860"] [id "942410"] [rev "2"] [msg "SQL Injection Attack"] [data "Matched Data: union select found within ARGS:keys: union select from users"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.0"] [maturity "9"] [accuracy "8"] [tag "OWASP_CRS/WEB_ATTACK/SQL_INJECTION"] [tag "WASCTC/WASC-19"] [tag "OWASP_TOP_10/A1"] [tag "OWASP_AppSensor/CIE1"] [tag "PCI/6.5.2"] [tag "paranoia-level/2"] [hostname "localhost"] [uri "/drupal/index.php/search/node"] [unique_id "WBuyJX8AAQEAAEdWTgQAAACL"]

$> cat alert | modsec-rulereport.rb --runtime --target --byid
# ModSec Rule Exclusion: 942410 : SQL Injection Attack
SecRule REQUEST_URI "@beginsWith /drupal/index.php/search/node" "phase:1,nolog,pass,id:10000,ctl:ruleRemoveTargetById=942410;ARGS:keys"



Alert 2:

[2020-03-09 12:53:18.862460] [-:error] 127.0.0.1:42014 XmYuLsHShsLLaLoWNWnOBwAAAAA [client 127.0.0.1] ModSecurity: Access denied with code 403 (phase 2). Operator GE matched 5 at TX:anomaly_score. [file "/home/dune73/data/git/crs-official/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "91"] [id "949110"] [msg "Inbound Anomaly Score Exceeded (Total Score: 10)"] [severity "CRITICAL"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [hostname "localhost"] [uri "/index.html"] [unique_id "XmYuLsHShsLLaLoWNWnOBwAAAAA"]

$> cat alert | modsec-rulereport.rb --runtime --target --byid

ADVISORY
--------

***This is not a rule exclusion. Do not paste this into your configuration.***

There is an alert on rule 949110. This rule has a special role in the rule set. It
examines the anomaly score of the incoming request. If the anomaly score is
equal or higher than the anomaly threshold, then the rule blocks the request.

You should therefore not disable this rule. Instead you should work on different
rules so you can avoid false positives and make sure the anomaly score is low.



Alert 3: 

[2021-06-03 22:54:45.858724] [-:error] - - [client 127.0.0.1] ModSecurity: Warning. Pattern match "(?i:(?:(?:s(?:t(?:d(?:dev(_pop|_samp)?)?|r(?:_to_date|cmp))|u(?:b(?:str(?:ing(_index)?)?|(?:dat|tim)e)|m)|e(?:c(?:_to_time|ond)|ssion_user)|ys(?:tem_user|date)|ha(1|2)?|oundex|chema|ig?n|pace|qrt)|i(?:s(null|_(free_lock|ipv4_compat|ipv4_mapped|ipv4|ipv ..." at ARGS:keys. [file "/apache/conf/owasp-modsecurity-crs-3.0.0-rc1/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf"] [line "860"] [id "942410"] [rev "2"] [msg "SQL Injection Attack"] [data "Matched Data: union select found within ARGS:keys: union select from users"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.0"] [maturity "9"] [accuracy "8"] [tag "OWASP_CRS/WEB_ATTACK/SQL_INJECTION"] [tag "WASCTC/WASC-19"] [tag "OWASP_TOP_10/A1"] [tag "OWASP_AppSensor/CIE1"] [tag "PCI/6.5.2"] [tag "paranoia-level/2"] [hostname "localhost"] [uri "/drupal/index.php/search/node"] [unique_id "WBuyJX8AAQEAAEdWTgQAAACL"]

$> cat alert | modsec-rulereport.rb --runtime --target --byid --metainformation --baseruleid 42410
# ModSec Rule Exclusion: 942410 : SQL Injection Attack
# Based on following alert:
# //localhost/drupal/index.php/search/node
# timestamp: 2021-06-03 22:54:45.858724 id: WBuyJX8AAQEAAEdWTgQAAACL
# alert: 942410 Matched Data: union select found within ARGS:keys: union...
# ruleset/version: OWASP_CRS/3.3.0
SecRule REQUEST_URI "@beginsWith /drupal/index.php/search/node" "phase:1,nolog,pass,id:42410,ctl:ruleRemoveTargetById=942410;ARGS:keys"

Of course, there are also single-letter variants for the command line options. -rTi brings the rule exclusion quoted above.

Download: modsec-rulereport.rb

The English tutorial Handling False Positives with the OWASP ModSecurity Core Rule Set has been adopted to the new script. The German one will be updated soon.