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