It has been a while since we have seen big development in the OWASP ModSecurity Core Rules. This is due to the fact, that the development took place in a separate branch named 3.0.0-dev which adopts many of the newer features and operators included in ModSecurity since 2.7; notably @detectSQLi and @detectXSS. When you take a closer look at the new rules, you realize quickly, that the whole file structure has been adopted. It looks quite unfamiliar if you got used to the 2.2.X rulesets.
I want to understand the differences between the rulesets and given the fact we are talking of several hundred rules, reading them one by one or following the changelog seems a daunting task. Let’s take a more behavioristic approach. Let’s see them in action.
The idea here is to setup two servers, one with Core Rules v2.2.9 and one with Core Rules v3.0.0-dev. Then configure a minimal set of local pages and have a vulnerability scanner examine the site. This won’t be a sophisticated venture into securing a site, but rather a report on how v2.2.9 reacts to a scan and what v3.0.0-dev does with the same requests.
For quick access and simplicity I used nmap first. Nmap comes with a lot of http scanning scripts and I ran them all one after another. However, they are more reconnaissance tools than attack scripts, so most of the requests went unnoticed by ModSecurity (well outside of thousands of fuzzying requests which were blocked with a 414). So I switched over to nikto. Nikto is not the newest scanner (and my version 2.1.4 is not the latest), but it’s very quick. And it is an attack scanner firing thousands of http exploits at a server. ModSecurity is alarmed by a lot of these, so we actually end up with many alerts and thus enough data to compare the two Core Rule versions.
Nikto has been called with the following commando:
$> nikto -h localhost -p 80
Core Rules v2.2.9 would let nikto carry out its tasks. But with v3.0.0-dev, there is a new feature: IP repudiation. As soon as the scanner had ramped up, ModSecurity realized what we are up to and started to block the source IP. This is done via an internal collection and based on the setting of the variable IP:BLOCK, rule 981140 will skip all further processing and rule 981175 will block the client IP. That’s a good feature. I do not know about false positives and I would not be surprised if legitimate users would be blocked by this rule. However, there is no need to allow a scanner to run thousands of requests against a website without reaction. In production some tuning might be due. In our case, tuning is also necessary, since the blocking mechanism cloaks the other rules which are not being executed. So I disabled the ip blocking as follows:
# No Blocking via IP repudiation, based on previous requests
SecRuleRemoveById 981140
SecRuleRemoveById 981175
Then I reran the test and ended up with 6179 requests for both rulesets.
Here is a graphical overview over the distribution of the anomaly scores:
And here the statistical data (generated using modsec-positive-stats.rb):
Core Rules v2.2.9 | Core Rules v3.0.0-dev
INCOMING Num of req. | % of req. |# of req| % of req.
Number of incoming req. (total) | 6197 | 100.0000% | 6197 | 100.0000%
Empty or miss. incoming score | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 0 | 217 | 3.5016% | 217 | 3.5016%
Reqs with incoming score of 1 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 2 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 3 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 4 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 5 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 6 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 7 | 0 | 0.0000% | 2826 | 45.6027%
Reqs with incoming score of 8 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 9 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 10 | 2850 | 45.9899% | 197 | 3.1789%
Reqs with incoming score of 11 | 0 | 0.0000% | 2 | 0.0322%
Reqs with incoming score of 12 | 0 | 0.0000% | 80 | 1.2909%
Reqs with incoming score of 13 | 201 | 3.2435% | 0 | 0.0000%
Reqs with incoming score of 14 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 15 | 142 | 2.2914% | 19 | 0.3065%
Reqs with incoming score of 16 | 3 | 0.0484% | 6 | 0.0968%
Reqs with incoming score of 17 | 0 | 0.0000% | 117 | 1.8880%
Reqs with incoming score of 18 | 52 | 0.8391% | 67 | 1.0811%
Reqs with incoming score of 19 | 2 | 0.0322% | 0 | 0.0000%
Reqs with incoming score of 20 | 2113 | 34.0971% | 26 | 0.4195%
Reqs with incoming score of 21 | 16 | 0.2581% | 25 | 0.4034%
Reqs with incoming score of 22 | 1 | 0.0161% | 2195 | 35.4203%
Reqs with incoming score of 23 | 76 | 1.2263% | 0 | 0.0000%
Reqs with incoming score of 24 | 93 | 1.5007% | 0 | 0.0000%
Reqs with incoming score of 25 | 155 | 2.5012% | 4 | 0.0645%
Reqs with incoming score of 26 | 16 | 0.2581% | 1 | 0.0161%
Reqs with incoming score of 27 | 5 | 0.0806% | 182 | 2.9369%
Reqs with incoming score of 28 | 11 | 0.1775% | 2 | 0.0322%
Reqs with incoming score of 29 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 30 | 13 | 0.2097% | 7 | 0.1129%
Reqs with incoming score of 31 | 8 | 0.1290% | 1 | 0.0161%
Reqs with incoming score of 32 | 23 | 0.3711% | 125 | 2.0171%
Reqs with incoming score of 33 | 5 | 0.0806% | 0 | 0.0000%
Reqs with incoming score of 34 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 35 | 6 | 0.0968% | 12 | 0.1936%
Reqs with incoming score of 36 | 0 | 0.0000% | 21 | 0.3388%
Reqs with incoming score of 37 | 0 | 0.0000% | 27 | 0.4356%
Reqs with incoming score of 38 | 8 | 0.1290% | 0 | 0.0000%
Reqs with incoming score of 39 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 40 | 0 | 0.0000% | 2 | 0.0322%
Reqs with incoming score of 41 | 0 | 0.0000% | 7 | 0.1129%
Reqs with incoming score of 42 | 0 | 0.0000% | 14 | 0.2259%
Reqs with incoming score of 43 | 2 | 0.0322% | 0 | 0.0000%
Reqs with incoming score of 44 | 3 | 0.0484% | 1 | 0.0161%
Reqs with incoming score of 45 | 1 | 0.0161% | 3 | 0.0484%
Reqs with incoming score of 46 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 47 | 0 | 0.0000% | 5 | 0.0806%
Reqs with incoming score of 48 | 10 | 0.1613% | 0 | 0.0000%
Reqs with incoming score of 49 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 50 | 1 | 0.0161% | 0 | 0.0000%
Reqs with incoming score of 51 | 2 | 0.0322% | 0 | 0.0000%
Reqs with incoming score of 52 | 0 | 0.0000% | 1 | 0.0161%
Reqs with incoming score of 53 | 52 | 0.8391% | 0 | 0.0000%
Reqs with incoming score of 54 | 3 | 0.0484% | 0 | 0.0000%
Reqs with incoming score of 55 | 0 | 0.0000% | 1 | 0.0161%
Reqs with incoming score of 56 | 81 | 1.3070% | 0 | 0.0000%
Reqs with incoming score of 57 | 0 | 0.0000% | 1 | 0.0161%
Reqs with incoming score of 58 | 2 | 0.0322% | 0 | 0.0000%
Reqs with incoming score of 59 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 60 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 61 | 8 | 0.1290% | 0 | 0.0000%
Reqs with incoming score of 62 | 0 | 0.0000% | 1 | 0.0161%
Reqs with incoming score of 63 | 3 | 0.0484% | 0 | 0.0000%
Reqs with incoming score of 64 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 65 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 66 | 2 | 0.0322% | 0 | 0.0000%
Reqs with incoming score of 67 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 68 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 69 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 70 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 71 | 4 | 0.0645% | 0 | 0.0000%
Reqs with incoming score of 72 | 0 | 0.0000% | 1 | 0.0161%
Reqs with incoming score of 73 | 1 | 0.0161% | 0 | 0.0000%
Reqs with incoming score of 74 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 75 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 76 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 77 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 78 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 79 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 80 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 81 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 82 | 0 | 0.0000% | 1 | 0.0161%
Reqs with incoming score of 83 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 84 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 85 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 86 | 1 | 0.0161% | 0 | 0.0000%
Reqs with incoming score of 87 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 88 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 89 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 90 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 91 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 92 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 93 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 94 | 1 | 0.0161% | 0 | 0.0000%
Reqs with incoming score of 95 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 96 | 1 | 0.0161% | 0 | 0.0000%
Reqs with incoming score of 97 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 98 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 99 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 100 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 101 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 102 | 1 | 0.0161% | 0 | 0.0000%
Reqs with incoming score of 103 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 104 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 105 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 106 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 107 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 108 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 109 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 110 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 111 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 112 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 113 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 114 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 115 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 116 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 117 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 118 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 119 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 120 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 121 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 122 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 123 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 124 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 125 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 126 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 127 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 128 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 129 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 130 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 131 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 132 | 1 | 0.0161% | 0 | 0.0000%
Reqs with incoming score of 133 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 134 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 135 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 136 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 137 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 138 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 139 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 140 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 141 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 142 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 143 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 144 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 145 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 146 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 147 | 0 | 0.0000% | 0 | 0.0000%
Reqs with incoming score of 148 | 1 | 0.0161% | 0 | 0.0000%
2.2.9 Avg: 15.8043 Median: 13.0000 Std. deviation: 9.5405
3.0.0-dev Avg: 14.3466 Median: 10.0000 Std. deviation: 8.7512
OUTGOING Num of req. | % of req. of req. | % of req.
Number of outgoing req. (total) | 6197 | 100.0000% | 6197 | 100.0000%
Empty or miss. outgoing score | 0 | 0.0000% | 0 | 0.0000%
Reqs with outgoing score of 0 | 6193 | 99.9354% | 6193 | 99.9354%
Reqs with outgoing score of 1 | 0 | 0.0000% | 0 | 0.0000%
Reqs with outgoing score of 2 | 0 | 0.0000% | 0 | 0.0000%
Reqs with outgoing score of 3 | 0 | 0.0000% | 0 | 0.0000%
Reqs with outgoing score of 4 | 4 | 0.0645% | 4 | 0.0645%
2.2.9 Avg: 0.0026 Median: 0.0000 Std. deviation: 0.1016
3.0.0-dev Avg: 0.0026 Median: 0.0000 Std. deviation: 0.1016
So for 2.2.9, almost all nikto requests triggered at least two rules and ended up with a
score of 10 or above. That is not the case with the 3.0.0-dev ruleset. Here, almost half of
the requests stayed below 10. But mind you, we disabled the rule 981175, which would
have stopped almost all these requests. An interesting feature of the new ruleset is
the cluster at the score of 22. This is higher than a similar cluster of the v2.2.9
ruleset at 20. So in this midrange, a lot of requests score a bit higher with the
new ruleset.
The highest substantial cluster of requests with the v3.0.0-dev ruleset hit a score of
32. With the old v2.2.9 rules, we have a cluster at a score of 56. The highest scoring
request with the v3.0.0-dev ruleset came in at 82:
“GET /submit.php?subject=<script>alert(‘Vulnerable’)</script>&story=<script>alert(‘Vulnerable’)</script>&storyext=<script>alert(‘Vulnerable’)</script>&op=Preview HTTP/1.1”
This request has the nikto test ID 000786. With the v2.2.9 ruleset, the very same
request scored 148.
So in the higher range, v2.2.9 seems to lead to higher scores. When we look at the
average and the median, they are slightly higher for 2.2.9 and the results
seem to be a bit more stretched out according to the standard deviation.
Now scoring a bit lower than before is no fault in itself. It all depends on the anomaly
threshold which you set. So when migrating adjusting the anomaly setting seems
important. A threshold of 10 would have stopped over 95% of all nikto requests with
the v2.2.9 ruleset. With the new one, almost 50% of the requests stay below 10.
With the http responses, there was no difference in my tests. That is not surprising, as
there is no application to exploit and thus no interesting responses to scan.
Let’s move to the rules themselves. Which rules are actually scoring? Here is an overview.
v2.2.9 RuleID | v2.2.9 Description | Hits | Hits | v3.0.0-dev Description | v3.0.0-dev RuleID | |
950000 | Session Fixation | 1 | 0 | Rule not triggering anymore in v3.0.0-dev | 950000 | |
950001 | SQL Injection Attack | 5 | 3 | SQL Injection Attack | 950001 | |
950005 | Remote File Access Attempt | 223 | 219 | OS File Access Attempt | 950005 | |
950006 | System Command Injection | 6 | Rule gone in v3.0.0-dev | |||
950011 | SSI injection Attack | 3 | Rule gone in v3.0.0-dev | |||
950103 | Path Traversal Attack | 178 | 190 | Path Traversal Attack (/../) | 950103 | |
New rule in v3.0.0-dev | 259 | Path Traversal At (/../) | 950104 | |||
950107 | URL Encoding Abuse Attack Attempt | 1 | 1 | URL Encoding Abuse Attack Attempt | 950107 | |
950109 | Multiple URL Encoding Detected | 67 | 67 | Multiple URL Encoding Detected | 950109 | |
950118 | Remote File Inclusion Attack | 141 | 141 | Possible Remote File Inclusion (RFI) Attack: Common RFI Vulnerable … |
950118 | |
950119 | Remote File Inclusion Attack | 2272 | 2272 | Possible Remote File Inclusion (RFI) Attack: URL Payload Used … |
950119 | |
950120 | Possible Remote File Inclusion (RFI) Attack: Off-Domain … | 2331 | 2331 | Possible Remote File Inclusion (RFI) Attack: Off-Domain Reference/Link |
950120 | |
950901 | SQL Injection Attack: SQL Tautology Detected. | 245 | 246 | SQL Injection Attack: SQL Tautology Detected. | 950901 | |
950907 | System Command Injection | 1 | 196 | Remote Command Execution (RCE) Attempt | 950907 | |
New rule in v3.0.0-dev | 1 | HTTP Header Injection Attack via payload (CR/LF deteced) | 950913 | |||
950921 | Backdoor access | 1 | Rule gone in v3.0.0-dev | |||
958001 | Cross-site Scripting (XSS) Attack | 105 | Rule gone in v3.0.0-dev, probably integrated into 973340-973343 | |||
958031 | Cross-site Scripting (XSS) Attack | 2 | Rule gone in v3.0.0-dev, probably integrated into 973340-973343 | |||
958051 | Cross-site Scripting (XSS) Attack | 243 | Rule gone in v3.0.0-dev, probably integrated into 973340-973343 | |||
958052 | Cross-site Scripting (XSS) Attack | 282 | Rule gone in v3.0.0-dev, probably integrated into 973340-973343 | |||
New rule in v3.0.0-dev | 3 | PHP Injection Attack: Configuration Directive Found | 958979 | |||
New rule in v3.0.0-dev | 67 | PHP Injection Attack: Variables Found | 958980 | |||
959071 | SQL Injection Attack | 2 | Rule gone in v3.0.0-dev | |||
959073 | SQL Injection Attack | 5 | Rule gone in v3.0.0-dev | |||
960008 | Request Missing a Host Header | 1 | 1 | Request Missing a Host Header | 960008 | |
960010 | Request content type is not allowed by policy | 5 | 1 | Request content type is not allowed by policy | 960010 | |
960011 | GET or HEAD Request with Body Content. | 17 | 17 | GET or HEAD Request with Body Content. | 960011 | |
960015 | Request Missing an Accept Header | 6079 | 6079 | Request Missing an Accept Header | 960015 | |
960024 | Meta-Character Anomaly Detection Alert – Repetative Non-Word … |
417 | Rule gone in v3.0.0-dev | |||
960032 | Method is not allowed by policy | 11 | 1 | Method is not allowed by policy | 960032 | |
960034 | HTTP protocol version is not allowed by policy | 13 | 13 | HTTP protocol version is not allowed by policy | 960034 | |
960035 | URL file extension is restricted by policy | 219 | 219 | URL file extension is restricted by policy | 960035 | |
960208 | Argument value too long | 1 | Misconfiguration by the author: Limit not set properly | |||
960209 | Argument name too long | 1 | Misconfiguration by the author: Limit not set properly | |||
960901 | Invalid character in request | 65 | 65 | Invalid character in request | 960901 | |
960911 | Invalid HTTP Request Line | 17 | 10 | Invalid HTTP Request Line | 960911 | |
970901 | The application is not available | 4 | 4 | The Application Returned a 500-Level Status Code | 970901 | |
973300 | Possible XSS Attack Detected – HTML Tag Handler | 246 | Rule gone in v3.0.0-dev | |||
973304 | XSS Attack Detected | 2 | Rule gone in v3.0.0-dev | |||
973305 | XSS Attack Detected | 15 | Rule gone in v3.0.0-dev | |||
973307 | XSS Attack Detected | 282 | Rule gone in v3.0.0-dev | |||
973331 | IE XSS Filters – Attack Detected. | 243 | Rule gone in v3.0.0-dev | |||
973334 | IE XSS Filters – Attack Detected. | 2 | Rule gone in v3.0.0-dev | |||
973335 | IE XSS Filters – Attack Detected. | 63 | Rule gone in v3.0.0-dev | |||
973336 | XSS Filter – Category 1: Script Tag Vector | 230 | 244 | XSS Filter – Category 1: Script Tag Vector | 973336 | |
973338 | XSS Filter – Category 3: Javascript URI Vector | 3 | 2 | XSS Filter – Category 4: Javascript URI Vector | 973338 | |
New rule in v3.0.0-dev | 247 | NoScript XSS InjectionChecker: HTML Injection | 973340 | |||
New rule in v3.0.0-dev | 15 | NoScript XSS InjectionChecker: Attribute Injection | 973341 | |||
New rule in v3.0.0-dev | 114 | Node-Validator Blacklist Keywords | 973342 | |||
New rule in v3.0.0-dev | 246 | XSS Attack Detected via Libinjection | 973343 | |||
973346 | IE XSS Filters – Attack Detected. | 15 | 15 | IE XSS Filters – Attack Detected. | 973346 | |
981173 | Restricted SQL Character Anomaly Detection Alert – Total # of … |
427 | Rule gone in v3.0.0-dev | |||
981227 | Apache Error: Invalid URI in Request. | 19 | 19 | Apache Error: Invalid URI in Request. | 981227 | |
981231 | SQL Comment Sequence Detected. | 71 | Rule gone in v3.0.0-dev | |||
981240 | Detects MySQL comments, conditions and ch(a)r injections | 3 | 3 | Detects MySQL comments, conditions and ch(a)r injections | 981240 | |
981242 | Detects classic SQL injection probings 1/2 | 9 | 9 | Detects classic SQL injection probings 1/2 | 981242 | |
981243 | Detects classic SQL injection probings 2/2 | 154 | 154 | Detects classic SQL injection probings 2/2 | 981243 | |
981245 | Detects basic SQL authentication bypass attempts 2/3 | 76 | 76 | Detects basic SQL authentication bypass attempts 2/3 | 981245 | |
981246 | Detects basic SQL authentication bypass attempts 3/3 | 29 | 29 | Detects basic SQL authentication bypass attempts 3/3 | 981246 | |
981249 | Detects chained SQL injection attempts 2/2 | 8 | 8 | Detects chained SQL injection attempts 2/2 | 981249 | |
981257 | Detects MySQL comment-/space-obfuscated injections and backtick … |
6 | 6 | Detects MySQL comment-/space-obfuscated injections and backtick … |
981257 | |
981260 | SQL Hex Encoding Identified | 3 | Rule gone in v3.0.0-dev | |||
New rule in v3.0.0-dev | 32 | SQL Injection Attack Detected via LibInjection | 981261 | |||
981276 | Looking for basic sql injection. Common attack string for mysql … |
3 | 3 | Looking for basic sql injection. Common attack string for mysql … |
981276 | |
981317 | SQL SELECT Statement Anomaly Detection Alert | 3 | Rule gone in v3.0.0-dev | |||
981318 | SQL Injection Attack: Common Injection Testing Detected | 161 | 125 | SQL Injection Attack: Common Injection Testing Detected | 981318 | |
981319 | SQL Injection Attack: SQL Operator Detected | 1 | 1 | SQL Injection Attack: SQL Operator Detected | 981319 | |
990002 | Request Indicates a Security Scanner Scanned the Site | 6079 | 6079 | Request Indicates a Security Scanner Scanned the Site | 990002 | |
990012 | Rogue web site crawler | 6079 | Rule gone in v3.0.0-dev | |||
990902 | Request Indicates a Security Scanner Scanned the Site | 0 | 2336 | Request Indicates a Security Scanner Scanned the Site | 990902 | |
TOTAL | 33275 | 28352 | TOTAL | |||
We see less hits for about half of the rules. They appear weaker, or they are gone
from the ruleset. About a third of the rules come in with exactly the same number
of rules and a bit more than a sixth of the rules bring more hits or they are new
rules.
I did not look into all the rules in detail. So it is likely, rules shifted
their ids, or they were consolidated. The github changelog might contain
this information.
For this blog post, I will only look at the most striking changes:
Rule 950104 (Path Traversal Attack) : New rule in v3.0.0-dev
This is a new and very simple rule looking at the URI patterns “..\” and “../”
It’s a sibling of 950103, but a lot easier to read.
The numbers are impressive: 359 new hits.
Rule 950907 (Remote Command Execution (RCE) Attempt) : Bigger teeth in v3.0.0-dev
This rule has been rewritten and enriched with a big number of system commands
out of a file named os-commands.data. The success is striking:
196 hits vs. 1 in the simple variant in the v2.2.9 ruleset.
Rule 950913 (HTTP Header Injection Attack via payload) : New rule in v3.0.0-dev
This new rule with a single hit is not newsworthy at all. But then I happened
to propose it for inclusion via a pull request.
To see this exotic regex
trigger an alert with a well-known attack scanner pleases me.
Rules 958001, 958031, 958051, 958052 (Cross-site Scripting (XSS) Attack) : Gone from v3.0.0-dev
These rules are all gone from the new version. There are new rules compensating
for the loss partly, but the new rules do not make up for the over 600 alerts
that this group of rules triggered.
Rule 958980 (PHP Injection Attack: Variables Found) : New rule in v3.0.0-dev
That’s a new rule based on items in the data file php-variables.data.
Nice one. Rule 958979 does the same with php-config-directives.data.
Rule 960024 (Meta-Character Anomaly Detection Alert – Repetative Non-Word … ) : Gone from v3.0.0-dev
This rule disappeared from the ruleset. It is likely, this simple ruleset
triggered a lot of false positives: \W{4,}
It is similar to the case of the rules 981172 and 981173 whose disappearance I
described in a recent blogpost.
960024 is the same type of shepherd dog that barks quickly and often
(417 times, mind you!) and hands out 3 anomaly scoring points.
I think it should be brought back.
Rules 973300, 973304, 973305, 973307, 973331, 973334, 973335 (Various XSS Rules) : Gone from v3.0.0-dev ruleset
Like the Anti-XSS rule described above, these are gone for good despite summing 800 alerts.
There are new Anti-XSS rules described below, but I do not think they make up for the
loss.
Rules 973340, 973341, 973342 (Various Anti-XSS rules) : New rules in v3.0.0-dev
This is a group of new rules aimed to prevent XSS. Especially 973340 brings
a very big Regex with obvious success and 247 hits.
This is nice but it does not cover the loss of the Anti-XSS rules mentioned above.
Rule 973343 (XSS Attack Detected via Libinjection) : New rule in v3.0.0-dev
So this is the rule with the new @detectXSS operator based on libinjection
from client9: https://libinjection.client9.com/, https://github.com/client9/libinjection.
This neat library brought 246 hits, so its inclusion is welcome. However,
there are issues. It has been a topic before on the ModSecurity mailinglist,
but I mention them here again: LibInjection seems to be a fine piece of code.
But the website comes with a broken SSL Certificate and a server error, the
Changelog on github is severely outdated and the inclusion of XSS detection
into the library is mostly undocumented as is the functioning of @detectXSS and
@detectSQLi in ModSecurity. 99% of the commits to libinjection were done by
the main developer.
If you want to know how this works, you will find little information beyond
slides presented at OWASP meetings. What I would like to see is a technical
description of how this parser works. If I would be happy with impressive
slides, I would go and buy a commerical product.
I have no idea of the code quality, but from what I can tell about the project
looking at the surface, libinjection does not look trustworthy.
Rules 981172, 981173 (Restricted SQL Character Anomaly Detection Alert) : Gone from v3.0.0-dev
981172 did not trigger any alarms, but its sibling 981173 did issue 427 alerts.
Like 96024, these are workhorses likely to trigger a lot of false positives. And
this is why they went away. I am working on a pull request to bring them back,
probably via an optional setting.
See this blogpost for a more detailed discussion.
Rule 981231 (SQL Comment Sequence Detected) : Gone from 3.0.0-dev
This rule was removed from the dev-tree of the Core Rules. It was aimed at
SQL comments. Maybe this was not deemed important enough, or a cause of
too many false positives. I can not tell. But 71 hits in my tests
may be enough to reconsider this step.
Rule 981261 (SQL Injection Attack Detected via LibInjection) : New rule in v3.0.0-dev
This is the rule with the new @detectSQLi operator based on libinjection.
Given the number of other SQLi rules triggered I actually expected more hits
here. But then all I know about libinjection are the impressive slides.
Given my tests, there was not the same haircut with Anti-SQLi rules like with
Anti-XSS. But @detectSQLi still does not compensate the ones that are gone.
Rule 981318 (SQL Injection Attack: Common Injection Testing Detected) : Rule with shorter teeth
This rule is no longer applied to cookies and it does not cover the same range of
characters anymore. See:
Targets old: SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|!REQUEST_COOKIES:/_pk_ref/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/*
Targets new: SecRule ARGS_NAMES|ARGS|XML:/*
Regex old: “(^[\”‘`´’‘;]+|[\”‘`´’‘;]+$)”
Regex new: “(^[\”‘`;]+|[\”‘`]+$)”
We lost about a quarter of the hits with this simplification.
Rule 990012 (Request Indicates a Security Scanner Scanned the Site) : Gone from v3.0.0-dev
This rule is gone from the ruleset. The loss of 6000 hits based on the
data file modsecurity_35_bad_robots.data is partially compensated in the
990902 rule, which received an extended pair of teeth. But we lost
more than 3000 alerts.
The reason for the removal could be, that this rule is redundant to 990002,
which was based on modsecurity_35_scanners.data. But in fact, the two
data files are complementary and both rules target the User-Agent.
The data file scanners-user-agents.data now used in rule 990002 received
some of the user agents in modsecurity_35_bad_robots.data, but far from all.
So I really do not know.
Rule 990902 (Request Indicates a Security Scanner Scanned the Site) : Rule with bigger teeth in v3.0.0-dev
990902 used to test only for 2-3 regexes in the former edition. Now the dataset was expanded.
Obviously to cover nikto as well. The feat is performed via the query string parameter
http://cirt.net/rfiinc.txt sent by nikto in thousands of cases.
The 2336 hits look impressive here and if a script kiddy attacker really makes
an approach using this tool, then the bells will go off. But all these
anti-scanner rules only work against the obvious scanning attempts, so we
should not trust them too much. The expansion of 990902 sure is a good thing.
So this is my overview over the development of the OWASP ModSecurity Core Rules 3.0.0.
There are interesting new features, but also important rules which disappeared. I
hope some of them can be brought back before the 3.0.0 ruleset is released to the public.
If you have questions or feedback, then please get in touch via mail or twitter.
Christian Folini, netnea, @ChrFolini