Snort Inline Part I

Introduction

Network Intrusion is an important aspect of network security. There's a
wide variety of Intrusion Detection Systems (IDSes) out there. While these
are extremely useful to gather information about an attack, or the
beginnings of an attack, e.g., a port scan, they can only inform us that
an attack has occurred. What would be really useful is a system that
actually blocks these attacks in real time. snort_inline is a system
designed to do just that.

This article describes how to compile, install, and test snort_inline.
snort_inline is a modification of the freely available snort package to
allow inspection and subsequent rejection of network packets, assuming
they meet certain predefined criteria. This constitutes an Intrusion
Prevention System (IPS), instead of just Intrusion Detection.

So, how does an IPS actually work? The system loads a large array of
signatures. These signatures take the form of a string of data
characteristic of some particular type of attack. When a data packet
enters the network, the IDS/IPS examines that data against its database
of signatures. If the data match, then the IDS/IPS takes appropriate
action. In the case of an IDS, the intrusion attempt will be logged,
whereas, in the case of an IPS, the system can drop the data packet, or
even sever the offending machine's connection.

To begin with, if you are running a Red Hat/Fedora system, you may need
the source code for your system's installed kernel. This may be true of
other systems, too; please see below for more information on why this is
required. It is also useful to have a Web server running, as this
article uses the Web service to validate snort_inline's behaviour. You
should not attempt this on a production server - at least not the first
time that you try this procedure.

snort_inline requires four packages to be installed in order to
configure it on a Fedora Core 3/4 box. This may be true of other systems,
too; please see below for more detail, later in the topic. We will assume
all files are downloaded into /home/snort/; please replace this with your
own download directory.

To begin with, you need the iptables source code. For reference, I used iptables-1.3.1
for this article. Once you have the source tarball, move it to
/usr/src/, untar it, cd into its tree, and run 'make' with the
install-devel option:

This will install the libipq library, allowing snort_inline to
communicate with iptables. iptables is responsible for accepting or
rejecting packets on the network interface.

Next, you need to build and install libnet, which is a high-level API
allowing snort to construct and inject packets into the network. The
version of libnet I used was libnet-1.0.2a,
as specified in snort_inline's docs. The newer version of libnet is, as
yet, incompatible with snort. Follow the instructions below, once you have
downloaded libnet-1.1.0.tar.gz:

Providing there are no errors, you can proceed to the next section. If
at this stage you do find errors, you may need to install other
packages. The third package required is pcre, the Perl-Compatible
Regular Expressions library. For reference, I used pcre-6.1.tar.gz.
Once you have this file downloaded, follow the steps below, to install
pcre:

Providing there are no errors, you can proceed to the next section.
Important: On Red Hat/Fedora systems, you will need to
perform an extra step before you can compile snort_inline. This has not
been tested on other systems, but, if your build fails later with the
error shown below...

...you may need to perform the corrective steps below: The build fails
because your glibc headers need to be updated [1], and this is why the kernel source is
required, as stated above. To temporarily fix this problem, please make the
following adjustments. This step assumes you have your kernel's source
installed, and that it resides in linux-2.6.9. This directory is likely to
change, depending on your kernel/distro version.

This step can always be reversed at a later date, should problems arise.
You now need to obtain the latest snort_inline package. For reference, I used
snort_inline-2.3.0-RC1.tar.gz
in this guide. Now, perform the steps outlined below.

If there are no errors, then congratulations: You have just successfully
compiled and installed snort_inline.

Initial Configuration

We need to perform just a few more tweaks to the snort_inline
configuration, before it is ready to be run. To begin with, we need to
modify snort_inline's configuration file, making it point to the correct
path in order to obtain its rules. These rules tell snort_inline which
packets are malicious, and which are normal traffic. A quick workaround
is to move the classification and reference rule files to the rules
folder, like so:

Save the file and exit. Eventually, we are going to set up snort_inline
to run as a daemon, i.e., as a background process, although it is
perfectly conceivable that you may prefer to run it as a normal process.
In fact, to begin with, we won't be running it as a background service,
either: running non-daemon mode will let us view snort_inline's output,
and ensure that it is running as expected, without any errors. We must
now check /etc/snort_inline/snort_inline.conf to ensure that the rules
pathspec is as required below. Load the file in your favourite text
editor, and modify the line

var RULE_PATH /etc/snort_inline/drop_rules

to

var RULE_PATH /etc/snort_inline/rules

We now need to create a directory for snort_inline, to log the malicious
activity.

mkdir /var/log/snort_inline

By default, all traffic flowing to the kernel and back to user space must
be intercepted by snort_inline, to check for malicious network packets.
The kernel accomplishes this by pushing the data into a queue using the
ip_queue module. You can load ip_queue and verify its presence as follows:

modprobe ip_queue
lsmod | grep ip_queue

Providing you get see a line similar to the one below, ip_queue is
running and ready to interface with snort_inline.

ip_queue 9945 0

Next, iptables must be configured to send the traffic to ip_queue. You
accomplish that redirection using the following line, which redirects
all network packets destined for port 80 to the ip_queue module. If the
server is running a Web daemon, then this is an easy way to verify that
iptables is working. It is not recommended that you test this on a
production server, as your Web users WILL experience downtime.

iptables -I INPUT -p tcp --dport 80 -j QUEUE

If you now try browsing a Web site hosted on the server from a different
machine, you should notice that your browser hangs. This is because all
packets are being routed to the ip_queue, and are awaiting release by
iptables. Once snort_inline is running in background, all that traffic
will be released to the Web server, which will reply to the user's
request in the usual manner.

Testing snort_inline

The snort_inline installation can now be tested using the command below:
snort_inline should begin to process the packets being held in the
ip_queue, and hence resume normal network activity.

You should see some text flash by, and snort_inline should present a
message similar to:

__== Initialisation Complete ==__

If so, congratulations; snort_inline is now running. Try making that
connection via your Web browser again, and you should now see the Web
page you expected.
If you get a message similar to that below, then you forgot to load the
ip_queue module:

Back on the snort_inline box, hit [ctrl+c] to end the current
snort_inline process. It is now time to add a test rule so that you can
see if snort_inline is actually working. In this example we are going to
drop all port 80 activity. To do this, you need to edit
/etc/snort_inline/rules/web-attacks.rules. Open it using your favourite
editor, and add the following line before the first "alert" statement,
but below the comments.

Note that all other lines in this file start with the word "alert". This
means that snort_inline will only log and alert malicious packets: it
WILL NOT DROP them. This will be addressed in a short while. Re-run
snort_inline again with the following command:

Try once more to make that Web page connection. You may be required to
hit [ctrl+F5] to force page refresh and prevent your browser using a
cached version. Your request should now fail. Let us now quickly check
the logs, to see if snort_inline captured the "malicious attempt." Back
on the snort_inline box, hit [ctrl+c] once more to stop the snort_inline
process, and use the following command:

cat /var/log/snort_inline/snort_inline_full

You should be presented with an output sequence similar to the following.

If so, congratulations for the third time; snort_inline has successfully
used your rule to drop the packets. The string "Port 80 connection
Initiated" was the line you entered into web-attacks.rules, above. We
can also view a more-abridged version, by issuing the command

In order to use snort_inline effectively, you must now remove the drop
rule inserted earlier. Edit the file
/etc/snort_inline/rules/web-attack.rules, and prepend # to the line you
added earlier, making;

The last step is to modify all the rule files, turning alert rules into
drop rules. This can be done with a simple command, which must be typed
out exactly. If you are unsure, please make a backup of the rules folder
before you type this command, something that should be done as a matter
of practice.

Returning Your System to Normal

Congratulations: you have just installed a working IPS. For
completeness's sake, the following instructions demonstrate how to stop
snort_inline and return your system to normal operation. Be advised that
you can alternatively accomplish this by simply rebooting the machine.

To stop snort, as it is now running in daemon mode, we need to find its
process ID number, and then issue a kill signal. To do this, run the
following command;

ps aux | grep snort_inline

This should present you with output similar to that below; the number we
are looking for is the "15705":

You can now go ahead and issue the kill command, as follows, where the
number following kill is the one obtained in the previous step.

kill 15705

This will exit snort, but ip_queue will still be receiving packets and
disrupting network traffic flow. As previously stated, in this example,
all port 80 traffic will be disabled. To re-enable this traffic, we must
remove the iptables rule with the following command:

iptables -D INPUT -p tcp --dport 80 -j QUEUE

Your server should now resume normal network activity on port 80.

Where Do We Go from Here?

This article has been a primer on the world of snort_inline. Next
month's piece will be dedicated to updating snort_inline's rules,
writing your own custom rules, and creating a snort_inline startup
script to enable it at boot-up.

[1] Rick Moen comments: I advise caution about fooling with
one's kernel headers. The old advice to do this by fetching new
kernel source and unpacking it to /usr/src/linux was always problematic,
and has now been obsoleted by better and less breakage-prone ways.
Short explanation: Your kernel header files used in compilation
need to always be compatible with the installed libc; therefore, you
should never fool with them, except by installing a new libc package
that furnishes new, matching headers.

Long explanation: Some kernel header files get invoked from locations
within /usr/include/linux, during compiles. Early in the history of
Linux, someone implemented the seemed-good-at-the-time notion of
not carrying such headers inside /usr/include/linux, but
rather -- to save disk space, perhaps? -- to symlink from there to those
same header files' locations within a kernel source code tree unpacked at
/usr/src/linux. Unfortunately, as you maintained your system over time,
newer kernel source trees' header files inevitably accumulated subtle
incompatibilities with the installed C library's entry points.
Eventually, compiles begin to fail for mysterious reasons.

The cause of this syndrome was understood early on, but the habit of
symlinking headers to /usr/src/linux locations became so ingrained
that it took until about 1999 to eradicate it from Linux
distributions, despite
Torvalds's repeated urgings and
exhaustive analysis
from the Answer Gang.

What the author calls "updating glibc headers" looks to this
commentator like an instance of the "symlink madness" Torvalds and others
tried for eight years to stamp out. I personally wouldn't go there. If
"the build fails" because of header problems, I'm betting you induced those
problems yourself through prior fooling with /usr/include/linux contents,
and your real cure is to stop doing that and let your system header files
remain the way your glibc package wrote them.

Pete has been programming since the age of 10 on an old Atari 800 XE.
Though he took an Acoustical Engineering degree from the world-renowned
ISVR in Southampton UK, the call of programming brought him back and he
has been working as a Web developer ever since. He uses both Linux and
Windows platforms. He still lives in the UK, and is currently living
happily with his wife.