System training with ModSecurity (avoiding false positives)

When using ModSecurity the system will trigger any sort of exception, giving false positives in many kind of situations. This article enumerates those exceptions we have found useful in every day’s life.

All these rules must be put in a specific file:

vi /etc/httpd/modsecurity-crs/activated_rules/modsecurity_crs_48_local_exceptions.conf

Add the following lines:

#Avoid Google Analytics false positives:
SecRuleUpdateTargetById 981172 !REQUEST_COOKIES:'/^__utm/'
SecRuleUpdateTargetById 950901 !REQUEST_COOKIES:'/^__utm/'

#Avoid 127.0.0.1
SecRule REMOTE_ADDR "^127.0.0.1$" "phase:1,t:none,nolog,allow,ctl:ruleEngine=Off,ctl:auditEngine=Off,id:9999"

#Request Missing an Accept Header -  Allow for Google Reader
SecRuleRemoveById 960015

#Avoid checks on some wordpress related posted arguments:
SecRuleUpdateTargetById 981173 "!ARGS:_wp_http_referer"
SecRuleUpdateTargetById 981173 "!ARGS:_wp_original_http_referer"
SecRuleUpdateTargetById 981173 "!ARGS:referredby"

#Avoid special encoding chars false positives
SecRuleRemoveById 960024

Another good way to avoid false positives is to set thresholds in the proper way: you have to edit the config file and set the score levels.

vi /etc/httpd/modsecurity-crs/modsecurity_crs_10_config.conf

than look at the lines

SecAction \
  "id:'900003', \
  phase:1, \
  t:none, \
  setvar:tx.inbound_anomaly_score_level=5, \
  setvar:tx.outbound_anomaly_score_level=4, \
  nolog, \
  pass"

You have to put something different into the tx.inbound_anomaly_score_level and tx.outbound_anomaly_score_level: values of 15 and 12 are ok!

SecAction \
  "id:'900003', \
  phase:1, \
  t:none, \
  setvar:tx.inbound_anomaly_score_level=15, \
  setvar:tx.outbound_anomaly_score_level=12, \
  nolog, \
  pass"

Then a restart…. and it’s up and running!

/etc/init.d/httpd restart

ModSecurity and Logrotate

As you may have read, we are using ModSecurity to filter out bad HTTP requests on our servers. In this little post you will learn how to integrate ModSecurity and Logrotate to work effectively together.

One of this technology’s fallback is that it logs an incredible amount of data to /var/log/modsec_audit.log (all this data is useful for debugging purposes, so we do not want to avoid logging at all)… The size of this file at the end of the day is HUGE…

To avoid this we have created a new logrotate script that handles all the work. To install it under CentOS type

vi /etc/logrotate.d/modsecurity

then insert the following lines:

/var/log/modsec_audit.log {
    rotate 1
    compress
    missingok
    notifempty
    sharedscripts
    postrotate
        /sbin/service httpd reload > /dev/null 2>/dev/null || true
    endscript
}

No need to restart, it does everything when logrotate runs by itself…

To complete the scenario, let’s have a look to the lines we have written:

rotate 1

tells logrotate to keep ONLY 1 copy of the file. This means that today at 4 am logrotates deletes the file modsec_audit.log.1.gz and creates a new one starting from modsec_audit.log.

compress

means that we do want a compressed archive of the file

postrotate
    /sbin/service httpd reload > /dev/null 2>/dev/null || true
endscript

forces a restart of Apache.

ModSecurity Sql Injections prevention

Today we had a long day, some nice people were tryin’ some sql injections in our applications. Unfortunately they got it quite easy against an old web application (sic). Our alerting system rang since 14.00 and from then we had a very intense afternoon…

The situation is easy to understand:

  • PHP is not such strong-typed language
  • sometimes the lazy programmer forgets to cast variables against their types…
  • and then somebody else finds a good way to retrieve informations from the database (and maybe from the system)

After the first few minutes-panic, we realized that the solution was to install ModSecurity on our system (we do run some LAMP machines, so we needed a module for Apache).

ModSecurity 2.7.7 on Scientific Linux 6.4

Dependencies

The ModSecurity’s installation process on Scientific Linux 6.4 is quite easy, first of all you have to install the necessary dependencies:

yum install libxml2 libxml2-devel httpd-devel pcre-devel curl-devel

ModSecurity

Than you can proceed with ModSecurity itself:

cd /usr/src
wget --no-check-certificate https://www.modsecurity.org/tarball/2.7.7/modsecurity-apache_2.7.7.tar.gz
tar -xzvf modsecurity-apache_2.7.7.tar.gz
cd modsecurity-apache_2.7.7
./configure
make
make install
cp modsecurity.conf-recommended /etc/httpd/conf.d/modsecurity.conf
cp unicode.mapping /etc/httpd/conf.d/unicode.mapping

OWASP CRS

ModSecurity needs a few rules to work on… so you have to install them and activate all…

cd /etc/httpd/
wget https://github.com/SpiderLabs/owasp-modsecurity-crs/tarball/master -O SpiderLabs-owasp-modsecurity-crs-2.2.8-8.tar
tar -xvf SpiderLabs-owasp-modsecurity-crs-2.2.8-8.tar
mv SpiderLabs-owasp-modsecurity-crs-7528b8b modsecurity-crs
cd modsecurity-crs
cp modsecurity_crs_10_setup.conf.example modsecurity_crs_10_config.conf
for f in `ls base_rules/` ; do ln -s /etc/httpd/modsecurity-crs/base_rules/$f activated_rules/$f ; done
for f in `ls optional_rules/ | grep comment_spam` ; do ln -s /etc/httpd/modsecurity-crs/optional_rules/$f activated_rules/$f ; done

General configuration

Then you can proceed to configure the Apache module:

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

Add the following line to the top of the file:

LoadModule security2_module modules/mod_security2.so

Activate the engine modifying the SecRuleEngine directive setting it On:

SecRuleEngine On

Put the following lines at the end of the file:

SecPcreMatchLimit 150000
SecPcreMatchLimitRecursion 150000
<IfModule security2_module>
    Include /etc/httpd/modsecurity-crs/modsecurity_crs_10_config.conf
    Include /etc/httpd/modsecurity-crs/activated_rules/*.conf
</IfModule>

Last, but very important, you have to add mod_unique_id to the apache conf file. Mod_unique_id is normally shipped with the apache package, but you have to activate it putting the right code in the right place… First enter the apache conf file with vi:

vi /etc/httpd/conf/httpd.conf

Put the following line (if not already there):

LoadModule unique_id_module modules/mod_unique_id.so

Tweaking

ModSecurity is very polite: it does what you tell it to do: after a few days you will discover a word of false positives… and this not so good….

Accordingly with Spiderlabs’ Blog there are two ways to let ModSecurity work:

  • Traditional Detection Mode (which is the default)
  • Anomaly Scoring Detection Mode – Collaborative Rules

I strongly encourage the use of the second one…. to activate it you have to follow these few steps.

First open the modsecurity_crs_10_config.conf file:

vi /etc/httpd/modsecurity-crs/modsecurity_crs_10_config.conf

Identify the following line:

SecDefaultAction "phase:1,pass,log"

and substitute it with

SecDefaultAction "phase:2,pass,log,noauditlog"

(the “log, noauditlog” part is to avoid ModSecurity logging to /var/log/modsec_audit.log)

Then identify the following lines:

#SecAction \
"id:'900004', \
phase:1, \
t:none, \
setvar:tx.anomaly_score_blocking=on, \
nolog, \
pass"

and uncomment the first one:

SecAction \
"id:'900004', \
phase:1, \
t:none, \
setvar:tx.anomaly_score_blocking=on, \
nolog, \
pass"

A restart…

After this you can restart apache and take a look at log files

/etc/init.d/httpd restart && tail -f /var/log/httpd/error_log

If you’ve done all right, you should read something like

[...] ModSecurity for Apache/2.7.7 (http://www.modsecurity.org/) configured.
[...] ModSecurity: APR compiled version="1.2.7"; loaded version="1.2.7"
[...] ModSecurity: PCRE compiled version="8.10"; loaded version="8.10 2010-06-25"
[...] ModSecurity: LIBXML compiled version="2.6.26"

That’s it! Enjoy your brand new protection system!