Playing with modsecurity

Playing with modsecurity

Mon 04 August 2014

What is modsecurity?

There are books and documentation that address this better than I can do here, but I will give a very brief introduction that hopefully will allow you to test modsecurity.

ModSecurity is a Web Application Firewall (WAF). This means that it sits in front of your web service and looking for looking for suspicious activity.

ModSecurity is free, open source, and has been developed since 2002.

ModSecurity is based on rulesets, which means that all traffic going through modsecurity must be tested against one or more rules. A rule can reject or accept traffic.

A rule is composed of 4 parts:

  • variables
  • operators
  • transformations
  • actions

The traffic goes through five phases:

  • phase 1: request headers
  • phase 2: request body
  • phase 3: response headers
  • phase 4: response body
  • phaase 5: logging

Each rule defines which of the 5 stages it should operate on.

Read more about the phases:

We can specify which parts of the traffic we want to work with (variables), such as:

  • ARGS

See complete list of variables here:

We can specify how we will analyze traffic (operators) such as:

  • string matching (@beginsWith, @rsub, @rx)
  • numerical (@eq, @ge, @gt)
  • validation (@validateByteRange, @validateSchema, @validateUrlEncoding) miscellaneous (@geoLookup, @verifyCC, @ipMatch)

See complete list of operators here:

We can modify the traffic (transformation), such as:

  • base64decode, base64encode, length
  • lowercase
  • sha1, md5

See complete list of transformations here:

We can do something about the traffic based on the rule matches or not (actions), such as:

  • are disruptive (allow, block, deny, drop, proxy, pass, redirect) affect rule flow (chain, skip, skipAfter)
  • affect metadata (id, phase, msg, rev, severity tag)
  • affect variables (capture, deprecatevar, setvar, setuid)

See complete list of actions here:

You can also connect multiple rules (chaining), build up hits then block on a given treshold (assign scores) and much more.

These are advanced topics that you can find more information on if you look at the "References / Links / Resources" at the end of this article.

When you see the first example of a rule you will hopefully recognize the structure that I have outlined above, and thus it should all be a little less scary.

When we install modsecurity we will also install what is called the "core-rule-set, crs," which is a collection of rules you can start with. This means you will not have to build rules from scratch.

The CRS collection is maintained by the OWASP project, and provides a set of rules to detect the most common attack vectors.

Install modsecurity

1: Add the EPEL repository.

# wget
# rpm -ivh epel-release-7-0.2.noarch.rpm

2: Install all available modsecurity packets.

# yum install mod_security

# yum install mod_security_crs

Which provides the following two items:

- mod_security.i686 : Security module for the Apache HTTP Server
- mod_security_crs.noarch : ModSecurity Rules

3: The install created a new folder for us in /etc/httpd/modsecurity.d.

# ls /etc/httpd/modsecurity.d/
activated_rules modsecurity_crs_10_config.conf

4: Look in the file "modsecurity_crs_10_config.conf". It is well documented and provides an indication of what possibilities we have.

# cat /etc/httpd/modsecurity.d/modsecurity_crs_10_config.conf

Geolocate your visitors

We want to know where IP addresses (our visitors) come from. This will allow us to block connections from countries such as are known to have large botnets.

Install the GeoIP database:

# mkdir -p /opt/modsecurity/lib/

# cd /opt/modsecurity/lib/

# wget

# gunzip GeoLiteCity.dat.gz

Update your configuration to use the GeoIP database:

Edit the file modsecurity_crs_10_config.conf, and remove comment on the following line to activate your GeoIP database.

155 #
156 # -- [[ GeoIP Database ]] -----------------------------------------------------------------
157 #
158 # There are some rulesets that need to inspect the GEO data of the REMOTE_ADDR data.
159 #
160 # You must first download the MaxMind GeoIP Lite City DB -
161 #
162 #
163 #
164 # You then need to define the proper path for the SecGeoLookupDb directive
165 #
166 # Ref:
167 # Ref:
168 #
169 #SecGeoLookupDb /opt/modsecurity/lib/GeoLiteCity.dat
171 #

Restart apache to load the new modsecurity configuration.

# apachectl restart

Ruleset that block based on geolocation:

Now that we have geolocation we want to block based on this. We want to allow only traffic from Norwegian IP addresses:

  • Create your own ruleset i /etc/http/modsecurity.d/activated_rules

vi /etc/httpd/modsecurity.d/activated_rules/modsecurity_custom_70_geoblock.conf

  • Paste the following content:

SecRule REMOTE_ADDR "@geoLookup" "id:5,phase:1,t:none,pass,nolog"
SecRule GEO:COUNTRY_CODE3 "!@streq NOR" "id:6,phase:1,t:none,log,deny,msg:'Client IP not from Norway'"

  • We now blocks all traffic that does not come from Norway.

Detect HTTP fingerprinting

We want to detect HTTP fingerprinting, and you can change the string attacker gets back. This means that we can trick the attacker into believing that our Web server is different than what it actually is.

  • Create a new file in /etc/http/modsecurity.d/activated_rules

# vi /etc/http/modsecurity.d/activated_rules/modsecurity_custom_70_http_fingerprinting.conf

  • Paste the following content

# Defeat HTTP fingerprinting

# Change server signature
SecServerSignature "Microsoft-IIS/6.0"

# Deny requests without a host header
SecRule &REQUEST_HEADERS:Host "@eq 0" "id:1,phase:1,deny"

# Deny requests without an accept header
SecRule &REQUEST_HEADERS:Accept "@eq 0" "id:2,phase:1,deny"

# Deny request that don't use GET, HEAD or POST
SecRule REQUEST_METHOD !^(get|head|post)$ "id:3,phase:1,t:lowerCase,deny"

# Only allow HTTP version 1.0 and 1.1
SecRule REQUEST_PROTOCOL !^http/1.(0|1)$ "id:4,phase:1,t:lowercase,deny"

# Add X-Powered-By header to mimic IIS
Header set X-Powered-By "ASP.NET 2.0"

# Remove the ETag header
Header unset ETag

Restart apache to load the new modsecurity configuration.

# apachectl restart

  • Note that we use a unique ID in our rules in the example above. You have different namespaces that are reserved for different purposes.
  • List of available and reserved ids can be found here:

Logging with modsecurity

One of the modsecurity strengths is the ability to log everything that happens. We can log to the web server's error.log, modsecurity_audit, or both. Default for most rules is to log to both log files.

Personally, I like to separate modsec messages in a separate log file because it could potentially be a lot of data in this log.

# tail -f /var/log/httpd/modsec_audit.log

If you need more data about what is happening, turn on debug logging:

  • vi /etc/httpd/conf.d/mod_security.conf

SecDebugLog /var/log/httpd/modsec_debug.log
SecDebugLogLevel 3


This section was created after puppet removed vital parts of my modsecurity configuration. I had to recreate my configuration from scratch.

  • If the module does not load, you must enter the following in /etc/httpd/conf.d/modsecurity.load

LoadModule security2_module modules/

<IfModule !mod_unique_id.c>
LoadModule unique_id_module modules/

  • We also need the following in /etc/httpd/conf.d/modsecurity.conf

<IfModule mod_security2.c>
# ModSecurity Core Rules Set configuration
IncludeOptional modsecurity.d/*.conf
IncludeOptional modsecurity.d/activated_rules/*.conf

# Default recommended configuration
SecRuleEngine On
SecRequestBodyAccess On
SecRule REQUEST_HEADERS:Content-Type "text/xml" \
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072
SecRequestBodyInMemoryLimit 131072
SecRequestBodyLimitAction Reject
SecRule REQBODY_ERROR "!@eq 0" \
"id:'200001', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2"
"id:'200002',phase:2,t:none,log,deny,status:44,msg:'Multipart request body \
failed strict validation: \

"id:'200003',phase:2,t:none,log,deny,status:44,msg:'Multipart parser detected a possible unmatched boundary.'"

SecPcreMatchLimit 1000
SecPcreMatchLimitRecursion 1000

SecRule TX:/^MSC_/ "!@streq 0" \
"id:'200004',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'"

SecResponseBodyAccess Off
SecDebugLog /var/log/httpd/modsec_debug.log
SecDebugLogLevel 0
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABIJDEFHZ
SecAuditLogType Serial
SecAuditLog /var/log/httpd/modsec_audit.log
SecArgumentSeparator &
SecCookieFormat 0
SecTmpDir /var/lib/mod_security
SecDataDir /var/lib/mod_security

References / Links / Resources

Owasp5023 - WAF MODSECURITY, with Ivan Ristic. (45 minutes, distributed across på 6 videos).

Modsecurity Reference Manual

Modsecurity Commercial and Community Support/Services

Open Web Application Security Project (OWASP)