Intrustion detection and prevention for Apache with mod-security

Posted by Steve on Tue 28 Dec 2004 at 19:35

mod-security is a simple intrusion detector and preventor for Apache, allowing you to wrap an additional layer of protection around your webserver.

mod-security is a rule-based IDS (intrusion protection system) which allows you to create rules describing abnormal requests to your webserver. When malicious requests are made which match your rules the request can be denied, and the details logged.

With the rise of recent PHP-based worms, (such as Santy.E, or the renamed version PhpIncludeWorm), which attempt to exploit any PHP script they find it's suddenly much more important to protect your server.

The real protection, of course, is to only install and use secure code but if you're not auditing the code yourself, and the author was careless you could suddenly find yourself attacked with no warning.

Because the mod-security module can examine all parameters passed to your server be they GET or POST requests it is a perfect place to detect and defend against these attacks.

Installing mod-security on Woody

If you're running a webserver with Debian's stable distribution you will discover that the module isn't available yet, it's only available in the testing or unstable branch. This leaves you with two choices:

  • Install the module from source
  • Install a backport

(A backport is a Debian package which has been produced by somebody targetting one of the older releases).

Neither of the two major sources of backports or has a module available for Woody, so we'll install it from source.

Installation from source does have a couple of drawbacks - it isn't going to be upgraded via APT, and it isn't going to work well if you upgrade your installation of Apache often.

Still for such a simple module this is a good choice, so long as you install it and keep track of updates yourself. (You could do this by subscribing to the mod-security-announce mailing list).

First of all download the code, currently you can download it and unpack it by running:

cd /tmp
tar -pzxvf mod_security-1.8.6.tar.gz

You can always find the latest version at the modsecurity website.

Once you've downloaded the source and unpacked it you will need to install the apache development headers - so that the code can build against it:

apt-get install apache-dev

Then to build it become root and execute the following command:

root@undecided:~# cd /tmp/mod_security-1.8.6/apache1
root@undecided:/tmp/mod_security-1.8.6/apache1# apxs -cia mod_security.c
gcc -DLINUX=22 -DEAPI -DTARGET="apache" -DHAVE_SET_DUMPABLE -DDB_DBM_HSEARCH=1 -DDEV_RANDOM=/dev/random -DUSE_HSREGEX -O1  -g -Wall -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fPIC -DSHARED_MODULE -I/usr/include/apache-1.3  -c mod_security.c
mod_security.c: In function `sec_logger':
mod_security.c:3474: warning: `nbytes' might be used uninitialized in this function
gcc -shared -o mod_security.o
[activating module `security' in /etc/apache/httpd.conf]
cp /usr/lib/apache/1.3/
chmod 755 /usr/lib/apache/1.3/
cp /etc/apache/httpd.conf /etc/apache/httpd.conf.bak
cp /etc/apache/ /etc/apache/httpd.conf
rm /etc/apache/

Don't be alarmed by the messages at the end, your apache configuration files should have been left undamaged - the installation script merely adds some basic settings, and then enables the module. None of this will take effect until Apache is restarted, but first we'll need to make changes.

Installing mod-security on an Unstable machine

As there is a package available for Debian's unstable and testing distributions we can install it simply by running the following command as root:

apt-get install libapache-mod-security
Configuring It

Following either of the previous instructions you should have some minimal configuration settings included in your Apache configuration file /etc/apache/httpd.conf.

Essentially there are two things we need to setup:

  • The logging and security options
  • The rules which detect attacks

As mod-security is a rule-based system we need to define the rules which "evil requests" must match to trigger our protection, then we need to setup the response the server will generate.

The general options are probably sufficient and are installed by default:

# Turn the filtering engine On or Off
SecFilterEngine On

# Make sure that URL encoding is valid
SecFilterCheckURLEncoding On

# Unicode encoding check
SecFilterCheckUnicodeEncoding Off

# Only allow bytes from this range
SecFilterForceByteRange 0 255

# Only log suspicious requests
SecAuditEngine RelevantOnly

# The name of the audit log file
SecAuditLog /var/log/apache/audit_log

# Debug level set to a minimum
SecFilterDebugLog /var/log/apache/modsec_debug_log
SecFilterDebugLevel 0

# Should mod_security inspect POST payloads
SecFilterScanPOST On

# By default log and deny suspicious requests
# with HTTP status 500
SecFilterDefaultAction "deny,log,status:500"

These settings turn on the code, disable incoming data which is outside the byte range 0-255, and setup the logfiles beneath /var/log/apache.

The last line says that the module should deny requests which match malicious patterns (which we've still to define), log them, and send back a 500 status code. (Which corresponds to server error).

Now we come to the fun part. We need to write the list of rules which will match non-legitimate requests. These will really depend upon your site and the kind of scripts you're using, so we can't list rules which are too generic.

What we can do is pretty impressive:

  • Match against values which are submitted
  • Match against the names of submitted parameters
  • Match against the output coming from the server
  • Match against cookies
  • Match against remote addresses.

A simple rule is to say that nobody should be sending a parameter with the value /etc/passwd - unless they are trying to exploit a vulnerable script which will allow arbitary file reading.

We can do this with the following rule:

SecFilter /etc/passwd

Similarly if there is a script upon our website which is written badly enough to allow a remote user to execute a command we can detect them trying to see who they are, or looking at files with these three rules:

SecFilter /bin/ls
SecFilter /bin/uname
SecFilter /usr/bin/whoami

The recent Santy.A worm can be matched by this rule:

SecFilterSelective ARG_highlight %27

Some of the other worms I've seen attempt to use wget to download scripts which they can then execute - so you can block those with:

SecFilter cd\x20/tmp
SecFilter wget\x20

There are different types of rules you can use, mostly we've used "SecFilter" which matches against a string. We can also use "SecFilterSelective" which allows us to match the contents of a named parameter.

Although we've defined the general action to take against matched rules we can customize the actions on a per-rule basis. For example if we wish we can cause a redirect with the following:

SecFilter /etc/passwd redirect:

This will send any request to a new URL.

Or if we wish we can execute a command to log the request:

SecFilter /bin/rm execute:/usr/local/bin/
Testing It

To test it we need to install a CGI script, or PHP script which is a gaping security hole - then show how this is mitigated by the use of mod-security. Whilst it is important to test the system, this method is potentially dangerous - and you should definitely make sure you remove the script when you're satisfied.

Save the following script somewhere within your document root, with a name such as "vulnerable.php":

<?  include( $file ); ?>

This PHP script is a gaping security hole - it allows a malicious attacker to read any file upon your system - because the "$file" parameter is supplied by the remote user, and isn't checked before it is used an attacker could request your /etc/motd file with something like the following request:

As we've enabled "password protection" in our rules above we should be able to test this works by requesting:

If the rules have been setup correctly then the following rule should match:

    SecFilter /etc/passwd

So, when you request that URL you should see a server error message - and the password file should be hidden.

If that worked then you can be sure that the module is active, and all you need to do is make sure that your rules are adequate - and remove the vulnerable PHP script!


There is a wealth of documentation which you might wish to read to get the most out of this module.

The primary source is the official module homepage:

Other interesting articles include:



Posted by Serge (213.224.xx.xx) on Wed 29 Dec 2004 at 22:49
[ View Serge's Scratchpad | View Weblogs ]
Or, when using Apache 2.0 on Sarge/Sid:
apt-get install libapache2-mod-security
Not sure about the configuration specifics... Serge van Ginderachter

[ Parent | Reply to this comment ]

Posted by Steve (82.41.xx.xx) on Thu 30 Dec 2004 at 16:09
[ View Steve's Scratchpad | View Weblogs ]

Yes, that's right.

Similarly for building from source you'd go into the apache2 directory:

oot@undecided:~# cd /tmp/mod_security-1.8.6/apache2
root@undecided:/tmp/mod_security-1.8.6/apache2# apxs -cia mod_security.c

Apart from that though configuration is identical between Apache 1.x and 2.x, load the module then setup the rules as you wish.


[ Parent | Reply to this comment ]

Posted by Anonymous (212.61.xx.xx) on Mon 3 Jan 2005 at 15:42
Great tips here, i like the apache libapache-mod-security :-D lets keep the damn, hackers out.

[ Parent | Reply to this comment ]

Posted by Anonymous (69.203.xx.xx) on Thu 10 Mar 2005 at 03:44
For the sake of completeness on Apache2:

apt-get install libapache2-mod-security

a2enmod mod-security

cp /usr/share/doc/libapache2-mod-security/examples/httpd2.conf.examp le-full /etc/apache2/conf.d

Rename the config file to something more descriptive, like security, and then edit it to suit your needs.

reload apache2

There are also a battery of tests included with the package. Thgese are located in /usr/share/mod-security/tests and can be run with a perl script located in that directory ( The tests simulate a series of attacks and give a you pass/fail result. (I can't remember if that was addressed above).

[ Parent | Reply to this comment ]

Posted by nigel_horne (212.159.xx.xx) on Fri 22 Jun 2007 at 11:44
That fails for me:

debian:/etc# apt-get install libapache2-mod-security
Reading package lists... Done
Building dependency tree... Done
E: Couldn't find package libapache2-mod-security

[ Parent | Reply to this comment ]

Posted by bignose (203.57.xx.xx) on Thu 12 May 2005 at 00:26
Note that the module is named mod_security (with an underscore), following the same pattern as most other Apache modules.

[ Parent | Reply to this comment ]

Posted by Anonymous (199.243.xx.xx) on Wed 2 Nov 2005 at 04:15
What about useing the filters

SecFilter /etc/[0-9a-z]
SecFilter /bin/[0-9a-z]
SecFilter /usr/[0-9a-z]
SecFilter /tmp/[0-9a-z]

So that any variable with the starting directory will be auto denied.

[ Parent | Reply to this comment ]

Posted by bclark (196.36.xx.xx) on Wed 17 May 2006 at 09:49

Whats kewl is that the mod security and gotroot team have offered their conf / rulset files.

Basically what I did was, wget the conf files from the links above and then just used "Include".

Whats kewl is that things like css, xss, false user agents, SQL injection, ldap injection, javascript and normal /bin file attempts are included in their rulsets.

To get this working you need mod_security 1.9 (else it moans).

For debian testing users (link from

Ive been running nikto against my test machine, so far so good.

Brent Clark

[ Parent | Reply to this comment ]

Posted by Anonymous (81.44.xx.xx) on Thu 22 Dec 2005 at 15:52

is there any document helping for running mod-security (chroot) + php + mysql + apache2 ?

Information on Security Focus is already checked but is not really focused on this way.

Thanks in advance!

[ Parent | Reply to this comment ]

Posted by Steve (82.41.xx.xx) on Thu 22 Dec 2005 at 16:10
[ View Steve's Scratchpad | View Weblogs ]

Not that I'm aware of I'm afraid.

However using the chroot function of mod-security is simple, and PHP/MySQL shouldn't be affected so long as you allow the MySQL connection to occur over a loopback socket instead of the chrooted socket that is used by default.

Using mod_security doesn't really change the basics...


[ Parent | Reply to this comment ]

Posted by hile (81.44.xx.xx) on Fri 23 Dec 2005 at 17:53
Hi Steve,

sorry about my ignorance but, how could it solve the problem about symbolic link inside jail? I mean:
I'm trying to run gallery (.deb) on a chrooted environment with mod-security and after cheking gallery directory (/usr/share/gallery/) I've found sym-links like
config.php /etc/gallery/config.php
setup /var/lib/gallery/setup

do I have to copy/move /var/lib/gallery/setup to the /chroot/... directory?
I know that it shouldnt be the correct way to configure it.

Is there any other method?

Thanks again!

[ Parent | Reply to this comment ]

Posted by Anonymous (166.77.xx.xx) on Wed 18 Feb 2009 at 19:35
Yes, mount the external directory into the jail via fstab.

/external_dir/dir_name /home/jail/dir_name none bind 0 0

[ Parent | Reply to this comment ]

Posted by jlps (62.3.xx.xx) on Tue 28 Mar 2006 at 20:02
Unfortunately, mod-security has been removed from Debian due to issues with the license (see BTS bug #352344)


[ Parent | Reply to this comment ]

Posted by Steve (82.41.xx.xx) on Tue 28 Mar 2006 at 22:36
[ View Steve's Scratchpad | View Weblogs ]

That is most unfortunate, since I use the module on a daily basis on several hosts.

Time for a free replacement, maybe ..


[ Parent | Reply to this comment ]

Posted by ajt (84.12.xx.xx) on Thu 13 Jul 2006 at 20:39
[ View Weblogs ]
See also:

on the How-To Forge Site.

"It's Not Magic, It's Work"

[ Parent | Reply to this comment ]

Posted by Anonymous (84.188.xx.xx) on Tue 26 Sep 2006 at 10:18
Unfortunately the module is only available in the "unstable"-section. If one is running a "testing"-system, as I am...

[ Parent | Reply to this comment ]

Posted by Steve (62.30.xx.xx) on Tue 26 Sep 2006 at 11:04
[ View Steve's Scratchpad | View Weblogs ]

Yes it was removed for licensing reasons - and was why I wrote mod_ifier which has the same idea, but less options.


[ Parent | Reply to this comment ]

Posted by ajt (204.193.xx.xx) on Tue 7 Nov 2006 at 08:30
[ View Weblogs ]
As far as I can tell it's silly incompatabilities. Mod_security is GPL, but it includes Apache headers which cannot be. I understand Debian have to be careful to not break the law themselves, but why can't the upstream open source developers get along better....?

"It's Not Magic, It's Work"

[ Parent | Reply to this comment ]

Posted by patricki (72.34.xx.xx) on Fri 7 Sep 2007 at 17:23
> I wrote mod_ifier

Really appreciate this. I see that there's a package for sarge, but wondering if there's a deb for etch (x86) in the works?

If not, assuming I can just install mod-ifier-0.8 in etch via source?

Thanks again for creating a free replacement.


[ Parent | Reply to this comment ]

Posted by Steve (82.32.xx.xx) on Sat 8 Sep 2007 at 23:29
[ View Steve's Scratchpad | View Weblogs ]

Not in the near future; I realised that the module is utterly broken for POST handling - which spoils it. I've never gotten round to fixing this due to lack of time :(


[ Parent | Reply to this comment ]

Posted by Anonymous (62.58.xx.xx) on Wed 19 Oct 2011 at 14:44
Tried this on Squeeze for apache2:
# apt-get install libapache2-mod-security
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package libapache2-mod-security

So tried your one:
apt-get install libapache-mod-security
Which was installed into the mods-enabled dir.
Sadly, your Sec* entries above fail:
# /etc/init.d/apache2 restart
Syntax error on line 219 of /etc/apache2/apache2.conf:
Invalid command 'SecFilterEngine', perhaps misspelled or defined by a module not included in the server configuration
Action 'configtest' failed.

[ Parent | Reply to this comment ]

Posted by Steve (90.193.xx.xx) on Wed 19 Oct 2011 at 14:45
[ View Steve's Scratchpad | View Weblogs ]

The package was removed from Debian some time ago. You've installed the Apache 1.x version on a system running Apache 2.x which is why the configuration file directive was unrecognised and not understood...


[ Parent | Reply to this comment ]

Posted by Anonymous (62.58.xx.xx) on Wed 19 Oct 2011 at 15:01
This is a shame. I'll have to think of something else other than mod-security.

[ Parent | Reply to this comment ]

Sign In







Current Poll

Will you stick to systemd as the default in Debian?

( 919 votes ~ 35 comments )