Optimized Lab-Setup to attack ModSecurity with Security Scanners


Damiano Esposito of ZHAW and I run a little test project where we want to measure the effectiveness of the OWASP ModSecurity Core Rule Set 3.0 (CRS3) under attack by several security scanners.

The testing is only about to start, but I would like to document the setup of the ModSecurity server a bit to give you an idea how we tried to optimize the research and the quality of the documentation.

The server is based on the lab configuration I described in a series of tutorials at netnea.com. Then I tweaked it a bit and added a convenient logfile helper script. Here you go.

Dynamic Paranoia Level and Anomaly Threshold

We are working with a single test server, but we want to run multiple test scenarios changing the CRS3 Paranoia Level and possibly the Anomaly Thresholds as we move along. I came to the conclusion it would be easiest to have the security scanner submit these values in his request for testing purposes. Here is how:

SecRule REQUEST_HEADERS:X-PL "!^[1-4]$" \
   "phase:1,id:1001,deny,log,msg:'X-PL header out of range (1-4)'"
SecRule REQUEST_HEADERS:X-PL "@unconditionalMatch" \
   "phase:1,id:1002,pass,nolog,setvar:tx.paranoia_level=%{MATCHED_VAR}"

SecRule REQUEST_HEADERS:X-THRESHOLD-IN "!^[0-9]+$" \
   "phase:1,id:1011,deny,log,msg:'X-THRESHOLD-IN header wrong format ([0-9]+)'"
SecRule REQUEST_HEADERS:X-THRESHOLD-IN "@unconditionalMatch" \
   "phase:1,id:1012,pass,nolog,setvar:tx.inbound_anomaly_score_threshold=%{MATCHED_VAR}"

SecRule REQUEST_HEADERS:X-THRESHOLD-OUT "!^[0-9]+$" \
   "phase:1,id:1021,deny,log,msg:'X-THRESHOLD-OUT header wrong format ([0-9]+)'"
SecRule REQUEST_HEADERS:X-THRESHOLD-OUT "@unconditionalMatch" \
   "phase:1,id:1022,pass,nolog,setvar:tx.outbound_anomaly_score_threshold=%{MATCHED_VAR}"

So I define three HTTP Request headers. For each of them I test the exact format in whitelisting style (integer digits) and if found correct, I set the respective level or thresholds for the active request. Piece of cake. But very helpful so we do not have to touch the server configuration between test runs.

Correlation of requests

Documentation and logging is key. We use the ModSecurity Audit Log of course; including all parts of that log. But we also want to make sure the log of the security scanner aligns with our log. The have a very granular timestamp (See the logfile tutorial), but timestamps are a poor way to correlate requests on a client and a server. So in addition, we have the security scanner submit a HTTP Request header named X-Test-ID that the server writes into the access log instead of the tracking cookie. The tracking cookie is a bit of a historical artifact in the extended log format I developed. But while I rarely use it, I never kicked it out and now this is a moment where we can make good use of it. So without changing my default log format (and breaking my tools extracting information out of the log), we can log this X-Test-ID header in the slot reserved for the tracking cookie.

In return, we send the request’s unique ID back to the client as a HTTP response header. The client will then save it automatically inside the collection of responses.

With these little changes to the default configuration, we have a convenient test server and a guarantee for complete journal of all test requests.

Logfile archive

When a test run is over, we need a little helper script to grab all the logs on the server, packing them and pushing them into an archive. I wrote a little script not worth quoting here that does this and assigns the packed archive an identifier (note to self: align with X-Test-ID!) and then restarts apache to start with a new set of logs.

Stay tuned for updates about the project, or follow Damiano Esposito and me on twitter.

Christian Folini