Showing posts with label snort. Show all posts
Showing posts with label snort. Show all posts

Saturday, February 28, 2015

Anomaly detection in Snort

I just got thoroughly confused when I found a statement in one whitepaper by SANS that Snort can do anomaly based detection. For me, anomaly based detection means that the software is capable of detecting something that deviates from the normal behavior in a profound ways and additionally, it wasn't possible to algorithmically define this deviated behavior in advance. Obviously, I started immediately to google around to find out more information about this since, lately, I was reading some surveys about research on anomaly based detection. This is still relatively unexplored area which means not much used in real-world scenarios.

After a bit of googling I found in Snort manual the following section:
2.2.3.4 Anomaly Detection 
TCP protocol anomalies, such as data on SYN packets, data received outside the TCP window, etc are configured via the detect_anomalies option to the TCP configuration. Some of these anomalies are detected on a per-target basis. For example, a few operating systems allow data in TCP SYN packets, while others do not. 
Turns out that the anomaly detection in Snort are actually anomalies that can be algorithmically codified (e.g. in TCP segment SYN bit is set and there is data in the segment). So, in conclusion, there is no algorithm for learning in standard Snort code.

That said, I found now defunct research project that experimented with anomaly based detection in Snort. By looking into the implementation, it turns out that the authors created plugin for Snort that was logging different features into textual log files. Those log files were then processed using R. In essence, this is good approach for experimentation but not for a production use.

Thursday, March 13, 2014

Installing Snort 2.9.6.0 on CentOS 6.5 64-bit

Some time ago I wrote a post about installing Snort 2.9.1 on CentOS 6. In the mean time I decided it's time to upgrade so the idea of this post is to document what changed with respect to that older post. In short, binary packages for CentOS 6 are now provided on the Snort's download page. So, you only need to download them and install (or install using URL). Yet, there is a problem with a libdnet dependency (I don't know which one was used during compilation, but it certainly wasn't the one in EPEL).

Compiling and installing

In case you want to rebuild them, the process is now almost without any problems. In the following text I'll assume that you started with a minimal CentOS installation with the following packages installed (and their dependencies, of course): gcc, make, bison, flex, autoconf, automake, rpmbuild.

First, download daq source rpm file. Before rebuilding it, you should install pcap-devel. This is actually something rpmbuild tool will warn you that you have to install. When you installed it, rebuild daq:
rpmbuild --rebuild daq
then, install it:
yum localinstall ~/rpmbuild/RPMS/x86_64/daq-2.0.2-1.x86_64.rpm
Next, for snort you'll need libdnet library which is in EPEL. So, first install EPEL:
yum install http://mirrors.neterra.net/epel/6/i386/epel-release-6-8.noarch.rpm
Then, install necessary packages:
yum install libdnet-devel zlib-devel
Those two aren't listed as dependencies in Snort's SRPM file, so you'll get some cryptic error message. Now, download Snort's srpm file and rebuild it using:
rpmbuild --rebuild snort-2.9.6.0-1.src.rpm
Now, install it using:
yum localinstall ~/rpmbuild/RPMS/x86_64/snort-2.9.6.0-1.x86_64.rpm
That's all there is for installation.

Configuring and running

I'll assume that you are installing a fresh instance, i.e. no previous configuration. In case there is previous installation be careful not to overwrite existing configuration. To configure snort you'll have to download snortrules archive. Then, unpack it:
mkdir ~/snort
tar xzf snortrules-snapshot-2960.tar.gz -C ~/snort
chown root.root ~/snort
Next you have to move files in their place. First, move basic configuration file:
mv -f snort/etc/* /etc/snort/
Note that I'm using force option of move command to overwrite existing files. Next, move rules to their place:
mv -i snort/rules snort/preproc_rules snort/so_rules /etc/snort/
Now, if you are using SELinux you should change context of the files you moved to /etc/snort directory. Do it using the following commands:
chcon -R system_u:object_r:snort_etc_t:s0 /etc/snort
chcon -R system_u:object_r:lib_t:s0 /etc/snort/so_rules/precompiled/RHEL-6-0/
You should now modify configuration file. Here is a diff of the changes I made:
--- snort.conf.orig 2014-03-13 11:25:53.889609831 +0100
+++ snort.conf 2014-03-13 11:37:32.419292894 +0100
@@ -42,16 +42,16 @@
 ###################################################

 # Setup the network addresses you are protecting
-ipvar HOME_NET any
+ipvar HOME_NET 192.168.1.0/24

 # Set up the external network addresses. Leave as "any" in most situations
 ipvar EXTERNAL_NET any

 # List of DNS servers on your network
-ipvar DNS_SERVERS $HOME_NET
+ipvar DNS_SERVERS 192.168.1.8,192.168.1.9

 # List of SMTP servers on your network
-ipvar SMTP_SERVERS $HOME_NET
+ipvar SMTP_SERVERS 192.168.1.20

 # List of web servers on your network
 ipvar HTTP_SERVERS $HOME_NET
@@ -101,13 +101,13 @@
 # Path to your rules files (this can be a relative path)
 # Note for Windows users:  You are advised to make this an absolute path,
 # such as:  c:\snort\rules
-var RULE_PATH ../rules
-var SO_RULE_PATH ../so_rules
-var PREPROC_RULE_PATH ../preproc_rules
+var RULE_PATH rules
+var SO_RULE_PATH so_rules
+var PREPROC_RULE_PATH preproc_rules

 # If you are using reputation preprocessor set these
-var WHITE_LIST_PATH ../rules
-var BLACK_LIST_PATH ../rules
+var WHITE_LIST_PATH rules
+var BLACK_LIST_PATH rules

 ###################################################
 # Step #2: Configure the decoder.  For more information, see README.decode
@@ -240,13 +240,13 @@
 ###################################################

 # path to dynamic preprocessor libraries
-dynamicpreprocessor directory /usr/local/lib/snort_dynamicpreprocessor/
+dynamicpreprocessor directory /usr/lib64/snort-2.9.6.0_dynamicpreprocessor/

 # path to base preprocessor engine
-dynamicengine /usr/local/lib/snort_dynamicengine/libsf_engine.so
+dynamicengine /usr/lib64/snort-2.9.6.0_dynamicengine/libsf_engine.so.0

 # path to dynamic rules libraries
-dynamicdetection directory /usr/local/lib/snort_dynamicrules
+dynamicdetection directory /etc/snort/so_rules/precompiled/RHEL-6-0/x86-64/2.9.6.0/

 ###################################################
 # Step #5: Configure preprocessors
And you can download the complete snort.conf file that worked for me. Be careful, you need to change IP addresses in the configuration file to match your environment.

Finally, create two empty files, /etc/snort/rules/white_list.rules and /etc/snort/rules/black_list.rules.

Now, you should be able to start Snort, i.e.
# /etc/init.d/snortd start
Starting snort: Spawning daemon child...
My daemon child 1904 lives...
Daemon parent exiting (0)                         [  OK  ]

Friday, July 20, 2012

Querying SNORT SQL database

When SNORT stores its data into SQL database then there is obvious question how to get data you would otherwise had in plain log files generated by SNORT. So, here is what I managed to deduce so far (note that the post will be extended as I learn more). In case you have comment/addition/correction please post a comment on this post. That is especially valid for SQL queries as I'm not an expert in that area and some of them might be suboptimal.

Few introductory words


To try the following examples you need working instance of MySQL database and SNORT that logs into database (directly or via barnyard2). If you have that, then run mysql command line client (or some equivalent) and select SNORT database. You are now ready to go...

This post is written using schema version 107. To find out which version of schema you have, run the following query:
mysql> select * from `schema`;
+------+---------------------+
| vseq | ctime               |
+------+---------------------+
|  107 | 2012-07-10 10:20:52 |
+------+---------------------+
1 row in set (0.00 sec)
Note the backticks! Namely, schema is MySQL's reserved word and if you don't use backticks, MySQL will report syntax error! Alternatively, you can use syntax database.tablename to avoid table name being treated as a reserved word.

Finally, because of screen size constraints, I'm limiting the output more often than not, here is what you'll see in that regard:
  1. In SELECT statement, I'm using LIMIT N keyword to get only first N rows.
  2. I'll explicitly enumerate fields to be returned in SELECT statement instead of using star (i.e. SELECT column1,column2 instead of SELECT *).
  3. I'll also use LEFT() function to limit number of characters retrieved from VARCHAR and similarly typed columns.

Examples of queries


The first thing you probably want to find out is how many alerts there were on a certain day, e.g. on a July 10th, 2012. This is easy, just run the following query:
mysql> select count(*) from event where timestamp between '2012-07-10' and '2012-07-11';
+----------+
| count(*) |
+----------+
|    12313 |
+----------+
1 row in set (0.01 sec)
Two things you should note about this query:
  1. All the generated events are stored in the table event. There is a column timestamp which stores timestamp when an event was generated.
  2. To select date range I'm using between/and keywords. I'm also shortening typing by providing only a date while time is assumed to be 00:00:00 so this query basically catches anything on July 10th, 2012, as requested.
I could equally well use the following query:
select count(*) from event where date(timestamp)='2012-07-10';
to get the same result, but in case I want a range instead of a single day, syntax using BETWEEN keyword is better.

To get number of events generated on a current day, use the following query:
mysql> select count(*) from event where date(timestamp)=date(now());
+----------+
| count(*) |
+----------+
|      178 |
+----------+
1 row in set (0.13 sec)
Note that we are using function NOW() to get current time and then we just extract date using DATE() function.

While we are at the table events, here is its structure:
mysql> show columns from event;
+-----------+------------------+------+-----+---------+-------+
| Field     | Type             | Null | Key | Default | Extra |
+-----------+------------------+------+-----+---------+-------+
| sid       | int(10) unsigned | NO   | PRI | NULL    |       |
| cid       | int(10) unsigned | NO   | PRI | NULL    |       |
| signature | int(10) unsigned | NO   | MUL | NULL    |       |
| timestamp | datetime         | NO   | MUL | NULL    |       |
+-----------+------------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
Only the timestamp column contains data in this table, other columns are links to other tables as follows:
  1. sid and cid are links to packet data, i.e. IP/TCP/UDP headers and associated data. Those are placed within separate tables which we'll talk about later.
  2. signature is link (foreign key) to signature table column sig_id
Ok, what about finding out number of events per day? Well, easy again, the following select statement will do that:
mysql> select count(*),date(timestamp) as count from event group by date(timestamp);
+----------+------------+
| count(*) | count      |
+----------+------------+
|    11689 | 2012-06-28 |
|    17904 | 2012-06-29 |
|     4353 | 2012-06-30 |
|     4322 | 2012-07-01 |
|    14198 | 2012-07-02 |
|     2977 | 2012-07-03 |
|    12313 | 2012-07-10 |
|    13014 | 2012-07-11 |
|     9126 | 2012-07-12 |
|     2642 | 2012-07-17 |
|     1527 | 2012-07-19 |
+----------+------------+
11 rows in set (0.07 sec)
I could use ORDER BY statement to get a day with largest number of alerts, otherwise they are sorted according to a day. In this case I used function DATE() to chop time part of the timestamp. Otherwise, I would get alerts broken down by minutes.

Ok, let's move on. What about finding out all types of events that occurred, or in other words, all signatures. Well, signatures that SNORT generates are stored in the table signature and simple query on this table will give us the answer what signatures were generated so far:
mysql> select sig_id,sig_name from signature;
+--------+-----------------------------------------------------------------------+
| sig_id | sig_name                                                              |
+--------+-----------------------------------------------------------------------+
|      1 | SCAN UPnP service discover attempt                                    |
|      2 | stream5: TCP Small Segment Threshold Exceeded                         |
|      3 | http_inspect: NO CONTENT-LENGTH OR TRANSFER-ENCODING IN HTTP RESPONSE |
|      4 | http_inspect: MESSAGE WITH INVALID CONTENT-LENGTH OR CHUNK SIZE       |
|      5 | stream5: Reset outside window                                         |
|      6 | ssh: Protocol mismatch                                                |
+--------+-----------------------------------------------------------------------+
6 rows in set (0.00 sec)
All in all, our SNORT instance generated six different signatures so far. The table signature has the following structure:
mysql> show columns from signature;
+--------------+------------------+------+-----+---------+----------------+
| Field        | Type             | Null | Key | Default | Extra          |
+--------------+------------------+------+-----+---------+----------------+
| sig_id       | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| sig_name     | varchar(255)     | NO   | MUL | NULL    |                |
| sig_class_id | int(10) unsigned | NO   | MUL | NULL    |                |
| sig_priority | int(10) unsigned | YES  |     | NULL    |                |
| sig_rev      | int(10) unsigned | YES  |     | NULL    |                |
| sig_sid      | int(10) unsigned | YES  |     | NULL    |                |
| sig_gid      | int(10) unsigned | YES  |     | NULL    |                |
+--------------+------------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)
The columns are:
  1. sig_id is primary key of this table.
  2. sig_name is textual representation of signature.
  3. sig_class_id
  4. sig_priority
  5. sig_rev
  6. sig_sid
  7. sig_gid
Ok, the next thing you might want to know is how many time each alert was generated. So, to achieve this use the following SQL query:
mysql> select sig_id,left(sig_name,30),count(*) from signature as s, event as e where s.sig_id=e.signature group by sig_name;
+--------+--------------------------------+----------+
| sig_id | left(sig_name,30)              | count(*) |
+--------+--------------------------------+----------+
|      4 | http_inspect: MESSAGE WITH INV |      109 |
|      3 | http_inspect: NO CONTENT-LENGT |      198 |
|      1 | SCAN UPnP service discover att |    55440 |
|      6 | ssh: Protocol mismatch         |     2360 |
|      5 | stream5: Reset outside window  |    33698 |
|      2 | stream5: TCP Small Segment Thr |      971 |
+--------+--------------------------------+----------+
6 rows in set (0.23 sec)
We had to do a join across two tables, signature and event. As you can see I got specific signatures with their count. Furthermore, I could order them so that I have most frequent ones on top (or bottom). Also, you should note that I'm using LEFT() function to make the output shorter in order to fit this post.

Ok, what about finding number of signatures generated on a specific day, say, today? Well, this is the same as the previous query but we only have to add one more condition, namely that the rows from the table event are taken into account only if timestamp is from today:
mysql> select sig_id,left(sig_name,30),count(*) from signature as s, event as e where s.sig_id=e.signature and date(e.timestamp)=date(now()) group by sig_name;
+--------+--------------------------------+----------+
| sig_id | left(sig_name,30)              | count(*) |
+--------+--------------------------------+----------+
|      6 | ssh: Protocol mismatch         |      226 |
|      5 | stream5: Reset outside window  |        2 |
|      2 | stream5: TCP Small Segment Thr |       40 |
+--------+--------------------------------+----------+
3 rows in set (0.14 sec)
Easy, the only difference from the previous query is shown in italic font. Now, let us move on. Suppose we want to know hosts that generated packets that triggered alerts. In order to do that we have to include table iphdr in the query. Table iphdr contains data from the IP header of captured packet. So, run the following SELECT statement:
mysql> select signature,count(*) as cnt,inet_ntoa(ip_src) from event,iphdr where event.cid=iphdr.cid and event.sid=iphdr.sid group by ip_src order by cnt;
+-----------+-------+-------------------+
| signature | cnt   | inet_ntoa(ip_src) |
+-----------+-------+-------------------+
|         3 |     1 | 192.168.1.44      |
|         5 |     1 | 192.168.1.89      |
|         5 |     1 | 192.168.1.27      |
|         5 |     1 | 192.168.1.5       |
|         5 |     1 | 192.168.1.120     |
|         5 |     1 | 192.168.0.21      |
+-----------+-------+-------------------+
6 rows in set (0.0 sec)
Ok, I have source IP addresses that triggered total of CNT number of alerts. Note that IP addresses are kept in a decimal form, so they have to be converted into dot form using inet_ntoa() MySQL function.

Here is the structure of iphdr table:
mysql> show columns from iphdr;
+----------+----------------------+------+-----+---------+-------+
| Field    | Type                 | Null | Key | Default | Extra |
+----------+----------------------+------+-----+---------+-------+
| sid      | int(10) unsigned     | NO   | PRI | NULL    |       |
| cid      | int(10) unsigned     | NO   | PRI | NULL    |       |
| ip_src   | int(10) unsigned     | NO   | MUL | NULL    |       |
| ip_dst   | int(10) unsigned     | NO   | MUL | NULL    |       |
| ip_ver   | tinyint(3) unsigned  | YES  |     | NULL    |       |
| ip_hlen  | tinyint(3) unsigned  | YES  |     | NULL    |       |
| ip_tos   | tinyint(3) unsigned  | YES  |     | NULL    |       |
| ip_len   | smallint(5) unsigned | YES  |     | NULL    |       |
| ip_id    | smallint(5) unsigned | YES  |     | NULL    |       |
| ip_flags | tinyint(3) unsigned  | YES  |     | NULL    |       |
| ip_off   | smallint(5) unsigned | YES  |     | NULL    |       |
| ip_ttl   | tinyint(3) unsigned  | YES  |     | NULL    |       |
| ip_proto | tinyint(3) unsigned  | NO   |     | NULL    |       |
| ip_csum  | smallint(5) unsigned | YES  |     | NULL    |       |
+----------+----------------------+------+-----+---------+-------+
14 rows in set (0.00 sec)
sid and cid columns are connection to event table, and to tcphdr and udphdr tables. The rest of the columns contain data from IP header. For example, ip_ver contains IP version. So, you can try to see how many protocol versions that triggered alerts there was:
mysql> select ip_ver,count(*) from iphdr group by ip_ver;
+--------+----------+
| ip_ver | count(*) |
+--------+----------+
|      4 |    92445 |
+--------+----------+
1 row in set (0.04 sec)
In my case, it was only IPv4. We can also do the same with the other fields, like which transport layer protocols were observed:
mysql> select ip_proto,count(*) from iphdr group by ip_proto;
+----------+----------+
| ip_proto | count(*) |
+----------+----------+
|        6 |    43076 |
|       17 |    49785 |
+----------+----------+
2 rows in set (0.04 sec)
Obviously, only two, UDP (id 17) and TCP (id 6). BTW, those numbers you can look up in /etc/protocols file on any Linux machine, or you can go to IANA.

To see all source IP addresses that triggered alerts we can use the following query:
mysql> select inet_ntoa(ip_src),count(*) from iphdr group by ip_src limit 5;
+-------------------+----------+
| inet_ntoa(ip_src) | count(*) |
+-------------------+----------+
| 10.61.34.152      |       20 |
| 85.214.67.247     |        2 |
| 134.108.44.54     |        2 |
| 192.168.5.71      |       10 |
| 192.168.102.150   |     2130 |
+-------------------+----------+
5 rows in set (0.00 sec)
Now, it can turn out that there are some IP addresses that we actually didn't expect and we want to know, when and what happened. Take for example the address 10.61.34.152 from the above output, let's see what this address generated:
mysql> select inet_ntoa(ip_src),inet_ntoa(ip_dst),count(*) from iphdr where inet_ntoa(iphdr.ip_src)='10.61.34.152' group by ip_dst;
+-------------------+-------------------+----------+
| inet_ntoa(ip_src) | inet_ntoa(ip_dst) | count(*) |
+-------------------+-------------------+----------+
| 10.61.34.152      | 239.255.255.250   |       20 |
+-------------------+-------------------+----------+
1 row in set (0.03 sec)
Using this query we see that all the packets were destined to address 239.255.255.250. A bit of grouping according to date:
mysql> select date(timestamp),count(*) from event,iphdr where (event.cid,event.sid)=(iphdr.cid,iphdr.sid) and inet_ntoa(ip_src)='10.61.34.152' group by date(timestamp);
+-----------------+----------+
| date(timestamp) | count(*) |
+-----------------+----------+
| 2012-07-02      |       20 |
+-----------------+----------+
1 row in set (0.03 sec)
we see that all events were generated on the same day. And what was the alert:
mysql> select signature.sig_name,count(*) from signature,event,iphdr where (event.cid,event.sid)=(iphdr.cid,iphdr.sid) and inet_ntoa(ip_src)='10.61.34.152' and event.signature=signature.sig_id group by sig_id;
+------------------------------------+----------+
| sig_name                           | count(*) |
+------------------------------------+----------+
| SCAN UPnP service discover attempt |       20 |
+------------------------------------+----------+
1 row in set (0.84 sec)
Well, all were UPnP service discovery requests.

One interesting thing, at least for me, is who sent ICMP Echo Request messages on the network. This is easy to determine using the following query:
mysql> select inet_ntoa(iphdr.ip_src) as SRC,inet_ntoa(iphdr.ip_dst) as DST,timestamp from event,iphdr,icmphdr where (icmphdr.sid,icmphdr.cid)=(event.sid,event.cid) and (iphdr.sid,iphdr.cid)=(event.sid,event.cid) and icmp_type=8 limit 3;
+-------------+--------------+---------------------+
| SRC         | DST          | timestamp           |
+-------------+--------------+---------------------+
| 192.168.1.8 | 192.168.1.55 | 2012-07-20 11:05:01 |
| 192.168.1.8 | 192.168.1.55 | 2012-07-20 11:05:01 |
| 192.168.1.8 | 192.168.1.55 | 2012-07-20 11:05:02 |
+-------------+--------------+---------------------+
3 rows in set (0.00 sec)

Obviousy, host with address 192.168.1.8 sent probes to host 192.168.1.55.

So much for now. Detailed info about DB schema used by SNORT can be found on this link.

In the end, my impression is that it is definitely much more easier and efficient to gather statistics using SQL database than plain files but that it is the best to use some tool that has all those queries predefined and to fall back to SQL only when you have some very specific requirement.

Thursday, June 28, 2012

Snort with MySQL support on 64-bit CentOS 6...

In one of the previous posts I wrote about compiling Snort 2.9.2.1 on 64-bit CentOS. The newest stable version of Snort now is 2.9.2.3 and I'll use that version from now on. But, the old post is still valid for compiling that new one, so there is no need for another post.

But, there is a problem. If  you tried to build Snort package with MySQL support like this:
rpmbuild --rebuild --with mysql snort-2.9.2.3-1.src.rpm
then you certainly got the following message:
<some unrelated configure script output>
checking for mysql...

**********************************************
  ERROR: unable to find mysqlclient library (libmysqlclient.*)
  checked in the following places
        /usr
        /usr/lib
        /usr/mysql
        /usr/mysql/lib
        /usr/lib/mysql
        /usr/local
        /usr/local/lib
        /usr/local/mysql
        /usr/local/mysql/lib
        /usr/local/lib/mysql
**********************************************

error: Bad exit status from /var/tmp/rpm-tmp.R2KI5J (%build)


RPM build errors:
    Bad exit status from /var/tmp/rpm-tmp.R2KI5J (%build)
Well, the problem is that on 64-bit CentOS (and RHEL derivatives, including Fedora) 64-bit libraries are in /lib64 and /usr/lib64 directories. The easiest way to circumvent that problem is to do the following.

First, install SRPMS file so that it is unpacked:
rpm -ivh snort-2.9.2.3-1.src.rpm
Then, go to ~/rpmbuild/SPEC directory, and open file snort.spec in some text editor. Search for the following block:
   if [ "$1" = "mysql" ]; then
        ./configure $SNORT_BASE_CONFIG \
        --with-mysql \
        --without-postgresql \
        --without-oracle \
        --without-odbc \
        %{?EnableFlexresp} %{?EnableFlexresp2} \
        %{?EnableInline}
   fi
It's somewhere around line 231. Modify it to include line         --with-mysql-libraries=/usr/lib64, i.e. it should now look like follows:
    if [ "$1" = "mysql" ]; then
        ./configure $SNORT_BASE_CONFIG \
        --with-mysql \
        --with-mysql-libraries=/usr/lib64 \
        --without-postgresql \
        --without-oracle \
        --without-odbc \
        %{?EnableFlexresp} %{?EnableFlexresp2} \
        %{?EnableInline}
   fi
Save and close file. Then, start snort build using the following command:
rpmbuild -bb --with mysql snort-2.9.2.3-1.src.rpm
And that should be it...

Saturday, October 1, 2011

Installing Snort 2.9.1 on 64-bit CentOS 6...

I just installed Snort 2.9.1 on CentOS 6, and since that wasn't straightforward process, I decided to document all the steps I did for a later reference. Also, maybe someone will find this useful so I placed it here.

The process of setting up Snort is divided into three phases, compilation, installation and configuration. Compilation phase is done entirely on auxiliary host, while installation and configuration phases are done on the target host, i.e. on the host where you wish to install snort.
Binary Snort packages from the download pages are all for 32 bit machines. Furthermore, SPEC file within provided SRPM has two bugs. The first one is that it wrongly links with libdnet.1 library that doesn't exist. I circumvented that problem as described below. The second problem is that not all pretprocessors are included into the final binary package. If you try to start snort and it fails with the following message in the log file:
FATAL ERROR: /etc/snort/snort.conf(463) Unknown preprocessor: "sip".
then this is manifestation of that problem. Apart from sip; imap, pop and reputation pretprocessors are also missing. I have fixed spec file, and made the new Snort SRPM package. If you trust me enough (but don't! :)), you can skip the compilation phase and obtain directly binary packages for daq and snort from my homepage. In that case, go to the installation phase and continue from there.

Compilation

As I said, the first problem with Snort is that on the download page there are no precompiled binaries for 64-bit versions of Linux distributions. Still there are SRPMS packages of Snort (extension src.rpm) and its prerequisite Daq so it isn't so bad. Download those packages, and rebuild them, first daq and then, after installing daq, snort itself. For rebuild process development environment is mandatory, i.e. compiler, development libraries, etc. Since probably you are going to run snort on firewall, or some machine close to firewall, it isn't good security practice to install development environment on target machine (i.e. firewall). So, find another machine with CentOS 6 and all the latest updates (or install one) and perform build process there. You'll need at minimum to have package rpm-build-4.8.0-16.el6.x86_64, afterwards, any missing package will be reported and you can install it using yum. So, install rpm-build package, and try to start build process (do this as ordinary user!):
rpmbuild --rebuild daq-0.6.1-1.src.rpm
If missing packages are reported then install them (as superuser) and try to start build process again. Note that libdnet you can find in EPEL repository. Repeat this until build process is successful. Binary package you'll find in the directory ~/rpmbuild/RPMS/x86_64/. Go there and install daq package:
yum localinstall --nogpgcheck daq-0.6.1-1.x86_64.rpm
Option nogpgcheck is necessary since we didn't sign binary package. Then, go back to directory where you downloaded daq and snort, and start snort build process:
rpmbuild --rebuild snort-2.9.1-1.src.rpm
This too can stop due to the missing packages, so install any required package and restart build process. Do this until build process is successful.
Now you have daq and snort packages ready in the build output directory ~/rpmbuild/RPMS/x86_64/. There are files daq-0.6.1-1.x86_64.rpm and snort-2.9.1-1.x86_64.rpm.

Installation

Transfer binary packages of snort and daq to the target machine and install them there:
yum localinstall --nogpgcheck daq-0.6.1-1.x86_64.rpm \
            snort-2.9.1-1.x86_64.rpm
It could happen also that you'll need additional packages, but any dependencies will be automatically retrieved and installed by yum. So, that's for the installation phase.

Build process, for whatever reason, wrongly got dependency on libdnet library, it looks for libdnet.1 instead of libdnet.so.1. To check if this is problem in your case, just try to start snort:
# /etc/init.d/snortd start
Starting snort: /usr/sbin/snort: error while loading shared libraries: libdnet.1: cannot open shared object file: No such file or directory
                                                           [FAILED]
In case the output looks like that one, you have the problem with libdnet.1 too. To solve it, to the directory /usr/lib64 and run there the following command:
# ln -s libdnet.so.1 libdnet.1
This is actually a hack, since build process has a bug, but as I didn't want to look or modify build process, this was easier to do and I did it that way.

The error with library libdnet was caused by the manually installed libdnet in /usr/local/ which had name libdnet.1 for whatever reason and that was picked by configure script. In other words, if you compile snort manually you'll not have that problem, only if you used old binary that I provided (now that is fixed!).
You'll also need to obtain snort rules and that requires you to register on Snort Web page. After registering, and downloading rules, unpack the archive you obtained in some directory. In the following text I'm using package snortrules-snapshot-2910.tar.gz from the September 1st, 2011 (and which was obtained on October 1st, 2011).

What you'll get is the following structure:
$ ls -1
etc
preproc_rules
rules
so_rules
Move directories preproc_rules, rules and so_rules into /etc/snort directory. Also, move the content of etc directory to /etc/snort directory overwriting any files there.

In case you have SELinux enabled snort will be prevented from starting because of wrongly labeled preprocessor plugins. This manifests itself with the following line in the log files:
FATAL ERROR: Failed to load /etc/snort/so_rules/precompiled/RHEL-6-0/x86-64/2.9.1.0//smtp.so: /etc/snort/so_rules/precompiled/RHEL-6-0/x86-64/2.9.1.0//smtp.so: failed to map segment from shared object: Permission denied
Of course, the exact paths will differ depending on your exact installation. Note that snort runs as unconfined process and until I find a way to confine it this can be solved by running the following command in the directory /etc/snort/so_rules/precompiled/RHEL-6-0/x86-64/2.9.1.0 (note that this is the directory reported in the log file!):
# chcon system_u:object_r:lib_t:s0 *
Configuration

The final step is snort configuration prior to running it. Master configuration is stored in the /etc/snort/snort.conf file, so open it with your favorite text editor and modify the following lines:
  1. Line that reads ipvar HOME_NET any (cca. 45th line). Replace any with you network address. In my case that was 192.168.1.0/24.
  2. Line that starts with dynamicpreprocessor directory words (cca. 234th line). Parameter is directory and change this parameter to /usr/lib64/snort-2.9.1_dynamicpreprocessor/.
  3. Immediately following the previous line is the line that starts with dynamicengine. Change the parameter of that line with the value /usr/lib64/snort-2.9.1_dynamicengine/libsf_engine.so.
  4. And, immediately following the previous line is the line that starts with words dynamicdetection directory whose parameter should be /etc/snort/so_rules/precompiled/RHEL-6-0/x86-64/2.9.1.0/.
  5. Also, you have to create two empty files, /etc/snort/rules/white_list.rules and /etc/snort/rules/black_list.rules. Alternatively, you can disable reputation pretprocessor (find line that begins with preprocessor reputation and comment out the whole block.
Additionally, open /etc/sysconfig/snort file and look if there is something you need to change. For example, in case you have multiple interfaces on which you would like to run snort, you'll have to configure them in that file.

Finally, start snort with the following command:
# /etc/init.d/snortd stop
and, if snort should be started during the boot process, also run the following command:
# chkconfig snortd on
And, that's it! :)

About Me

scientist, consultant, security specialist, networking guy, system administrator, philosopher ;)

Blog Archive