How To Troubleshoot Mod_Security Rules

So you’ve read all my posts about how wonderful and necessary Mod_Security is and decided to configure it on your server. You activate a bunch of new rules from GotRoot or OWASP and now suddenly nobody can access your website, you can’t create new posts, or things are otherwise FUBAR – NOW what do you do?

First – don’t panic. Premade Modsecurity rulesets have hundreds of rules that must work across a variety of websites and CMS’s. They are usually 99% perfect, but there is always that 1% that may cause problems on your particular site or configuration. If you are coming to this post via Google, and you are already panicking, just go into your HTTP.CONF or MODSEC2.CONF file (you will need to figure out where your ModSecurity directives are being stored) and add the following line:
SecFilterEngine Off
Then restart Apache. This should stop Mod_Security from blocking anything, but still let you see what it’s doing in the logs. Now you can relax and start troubleshooting.

Troubleshooting Mod_Security 2.5:
The first step is to identify which rule is blocking your users or breaking your site. To see what is happening, check your Apache Error log or your Mod_Security log. In your logs, you will see something like this:

Pattern match "(?:cd |\;|php |echo |perl |killall |python |rpm |yum |apt-get |emerge |lynx |links |mkdir |elinks |wget |lwp-(?:download|request|mirror|rget) |id|uname |cvs |svn |(?:s|r)(?:cp|sh) |net(?:stat|cat) |rexec |smbclient |t?ftp |ncftp |curl |telnet |g?cc |cp ..." at REQUEST_URI. [file "/etc/modsecurity/10_asl_rules.conf"]
[line "587"] [id "340037"] [rev "3"] [msg " - FREE UNSUPPORTED DELAYED FEED - WAF Rules: Generic command injection"] [severity "CRITICAL"] 340037 [07/Jan/2011:22:43:29 --0800]
Pattern match "(?:cd |\;|php |echo |perl |killall |python |rpm |yum |apt-get |emerge |lynx |links |mkdir |elinks |wget |lwp-(?:download|request|mirror|rget) |id|uname |cvs |svn |(?:s|r)(?:cp|sh) |net(?:stat|cat) |rexec |smbclient |t?ftp |ncftp |curl |telnet |g?cc |cp ..." at REQUEST_URI. [file "/etc/modsecurity/10_asl_rules.conf"] [line "587"] [id "340037"] [rev "3"] [msg " - FREE UNSUPPORTED DELAYED FEED - WAF Rules: Generic command injection"] [severity "CRITICAL"]
[07/Jan/2011:22:43:29 --0800] THcUgdXS8AADiSIm4AX 42556 80
GET /modules/forum/hide-comments.png HTTP/1.1
User-Agent: Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5
Accept: */*
Accept-Language: en-us
Accept-Encoding: gzip, deflate

Look through the log for the “id” and file – in the example above, it’s [file/etc/modsecurity/10_asl_rules.conf] and the ID is rule #340037. Now you know what mod_security file to focus on (10_asl_rules.conf) and where in that file to start looking (rule/id 340037).

Open up file 10_asl_rules.conf and search until you find 340037 –

Rule 340037 looks like this:

# Rule 340037: generic attack signature
SecRule REQUEST_URI "(?:cd |\;|php |echo |perl |killall |python |rpm |yum |apt-get |emerge |lynx |links |mkdir |elinks |wget |lwp-(?:download|request|mirror|rget) |id|uname |cvs |svn |(?:s|r)(?:cp|sh) |net(?:stat|cat) |rexec |smbclient |t?ftp |ncftp |curl |telnet |g?cc |cpp |g\+\+ |/bin/(xterm|id|bash|sh|echo|kill|chmod|ch?sh|python|perl|nasm|ping|mail|ssh))" \
"id:340037,rev:3,severity:2,msg:' - FREE UNSUPPORTED DELAYED FEED - WAF Rules: Generic command injection'"

Now you need to figure out what it is about this rule that is going wrong, so back to the error log:
The error (above) says “Pattern match” (then all the match-rules) at REQUEST_URI. “REQUEST_URI” is the Mod_Security directive to inspect the URL being requested. (For a list of all the directives, check the MODSECURITY online-manual). To see what the URL was, find the GET command a little further down – in the example above, it’s GET /modules/forum/hide-comments.png

So we now know that rule #340037 located in file 10_asl_rules.conf does not like “modules/forum/hide-comments.png” – So let’s figure out why.

Rule 340037 (above) is made up of just a few lines (like most rules). The first line, starting with the ‘#’ is a comment describing the rule: # Rule 340037: generic attack signature

The next line:
"SecRule REQUEST_URI "(?:cd |\;|php |echo |perl |killall |python |rpm |yum |apt-get |emerge |lynx |links |mkdir |elinks |wget |lwp-(?:download|request|mirror|rget) |id|uname |cvs |svn |(?:s|r)(?:cp|sh) |net(?:stat|cat) |rexec |smbclient |t?ftp |ncftp |curl |telnet |g?cc |cpp |g\+\+ |/bin/(xterm|id|bash|sh|echo|kill|chmod|ch?sh|python|perl|nasm|ping|mail|ssh))"

Basically says if the URL matches this very complex regular expression, then do what’s in the next line, which reads:
"id:340037,rev:3,severity:2,msg:' - FREE UNSUPPORTED DELAYED FEED - WAF Rules: Generic command injection'"

This ID’s the rule as ‘340037’ with revision#3, sets the severity level for logging, and assigns the message to show in the logs – because elsewhere in the mod_security configuration the default action as been set to “deny” – this page/url will been blocked – but WHY?

To figure out what it is about about the path “modules/forum/hide-comments.png” that the expression above does not like you can try to read-through it and figure it out (good luck!) or use a RegEx (Regular Expression) tool such as to see what the match is. In our example, it is the “id” in the path ‘hide-comments.png’ that matches (?:download|request|mirror|rget) |id|uname |cvs |svn |(?:s|r) in the rule.

Now we know where and why Mod_Security has blocked this particular page.. Now what?

Now you have to decide what to do about it – here are some choices:
1) Disable the entire rule
2) Disable the rule only for this particular URL (“ByLocation”)
3) Create a slightly modified custom rule that overrides this rule and works with this particular page/URL

Which route you take depends on many things and I can’t tell you which to choose – that part you will have to figure out on your own.

Option 1 – Disable the entire rule:
You could simply delete all the lines associated with rule 340037, or comment them out by putting a ‘#’ on each line, then restart Apache. The problem with this method is that if you ever update your rules, your changes will be overwritten with the new file, and the rule would be active again. A better way to disable the rule is to add the following line in your HTTP.CONF or MODSEC2.CONF file:

SecRuleRemoveById 340037

Restart Apache and now rule 340037 will be disabled

Option 2 – Disable the rule just for this particular URL:
You can tell Mod_security to ignore rule 340037 only for the URL /modules/forum/hide-comments.png by adding the following line to your HTTP.CONF or MODSEC2.CONF file:

<LocationMatch modules/forum/hide-comments.png>

SecRuleRemoveById 340037


Restart Apache and now rule 340037 will be ignored/disabled only for the URL /modules/forum/hide-comments.png

Option 3 – Replace rule 340037 with your own, slightly customized rule:
You can create your own custom rule that does not include the “id” match, then disable the ‘real’ rule 340037.

First, create a new file named something like “99_my_rules.conf” and place in the same directory as your other Mod_Security rules (probably at /etc/modsecurity). Copy and paste rule 340037 from 10_asl_rules.conf and put into your new custom-rules file and make the following changes:

Change “340037” to 990037 – This will keep you from confusing it with the real rule “340037”

Change the message from : ‘ – FREE UNSUPPORTED DELAYED FEED – WAF Rules: Generic command injection’
to something like: ‘My custom rule that replaces 340037’

Find the part of the expression that we want to get rid of – in this case it is the “id” at this part:

|request|mirror|rget) |id|uname |cvs |svn

Remove the “id|”, which should leave just:

|request|mirror|rget) |uname |cvs |svn

and save the file.

In your HTTP.CONF or MODSEC2.CONF file, disable the original rule 340037 by following Option #1 above

Add the following line in your HTTP.CONF or MODSEC2.CONF file to tell Mod_security to load your new custom rules:
Include /etc/modsecurity/99_my_rules.conf — place this line right after the other rules listed. Be sure to use the correct path for your system.

Restart Apache and now the original rule 340037 will be disabled and your new rule 990037 will be active. If you ever need to create any other custom rules, just add them into your new 99_my_rules.conf file (and restart Apache).

Some things to keep in mind when changing Mod_Security rules:
Before you change any files, make a copy of it first. It’s very easy to make a syntax error, or screw something up.

Each time you restart Apache, make sure it actually starts and check your site! If Apache will not start, just put back the backup file that you made, and start Apache again – then figure out what went wrong.

If you disabled blocking in Mod_Security with the SecFilterEngine Off directive, be sure to change it back to SecFilterEngine ON

Most important – watch your logs very closely and verify that ModSecurity is only blocking things you really want blocked.

Questions? Did I miss anything? Post a comment!

4 thoughts on “How To Troubleshoot Mod_Security Rules

  1. Randy,
    Looks to me like the RegEx checker URL is located at
    Thank you for making this available. Good resource.

  2. Just wanted to let you know that this is the easiest-to-follow tutorial I’ve seen thus far on working with mod_security. Thanks a bunch – great work!

Leave a Reply to Attila Hooper Cancel reply

Your email address will not be published.