Saturday, January 25, 2014

Suricata 2.0beta2 as IPS on Ubuntu 12.04

Today I decided to install Suricata, the open source intrusion detection and prevention engine from the Open Information Security Foundation (OISF), as an IPS.

I've been running Suricata in IDS mode through Security Onion on and off for several years, but I never tried Suricata as an IPS.

I decided I wanted to run Suricata as a bridging IPS, such that it did not route traffic. In other words, I could place a Suricata IPS between, say, a router and a firewall, or between a router and a host, and neither endpoint would know the IPS was present.

Looking at available documentation across the Web, I did not see specific mention of this exact configuration. It's entirely possible I missed something useful, but most people running Linux as a bridge weren't using Suricata.

Those running Linux as a bridge sometimes enabled an IP address for the bridge, which is something I didn't want to do. (True bridges should be invisible to endpoints.)

Of course, to administer the bridge system itself, you ensure the box has a third interface and you assign that interface a management IP address.

I also noticed those using Suricata as an IPS tended to configure it as a router, giving IP addresses to the internal and external IP addresses. I wanted an invisible bridge, not a router.

The hardware I used for the bridge was a 2003-era Shuttle small form factor system with 512 MB RAM, two NICs (eth0 and eth1), and a wireless NIC (wlan0). I installed Ubuntu Server 12.04.3 LTS. I tried installing the 64 bit version but realized the box was too old for 64 bit. Once I tried a 32 bit installation I was working in no time.

The first step I took was to create the bridge. I wanted to deploy the system between a router and an endpoint with IP address 192.168.2.142, like this:

router <-> eth0/Linux bridge/eth1 <-> 192.168.2.142

These are the commands to create the bridge. This how-to was useful.

$ sudo apt-get install bridge-utils
$ sudo brctl addbr br0
$ sudo brctl addif br0 eth0
$ sudo brctl addif br0 eth1
$ sudo ifconfig eth0 0.0.0.0
$ sudo ifconfig eth1 0.0.0.0
$ sudo ifconfig br0 up

With the bridge working, I could reach 192.168.2.142, the endpoint host, through the Ubuntu Linux bridge system. If I wanted to, I could watch traffic with Tcpdump on br0, eth0, or eth1.

Next I needed to install Suricata. I decided to use the beta packages published by OISF as described here. I also had to install python-software-properties as shown in order to have add-apt-repository available.

$ sudo apt-get install python-software-properties

$ sudo add-apt-repository ppa:oisf/suricata-beta
You are about to add the following PPA to your system:
 Suricata IDS/IPS/NSM beta packages

http://www.openinfosecfoundation.org/
http://planet.suricata-ids.org/
http://suricata-ids.org/

Suricata IDS/IPS/NSM - Suricata is a high performance Network IDS, IPS and Network Security Monitoring engine.

Open Source and owned by a community run non-profit foundation, the Open Information Security Foundation (OISF).
 Suricata is developed by the OISF, its supporting vendors and the community.

This engine is not intended to just replace or emulate the existing tools in the industry, but will bring new ideas
 and technologies to the field.

This new Engine supports:

Multi-Threading - provides for extremely fast and flexible operation on multicore systems.
File Extraction, MD5 matching - over 4000 types of file recognition/extraction transmitted live over the wire.
TLS/SSL certificate matching/logging
Automatic Protocol Detection (IPv4/6, TCP, UDP, ICMP, HTTP, TLS, FTP, SMB )
Gzip Decompression
Fast IP Matching
Hardware acceleration on CUDA and GPU cards

and many more great features -
http://suricata-ids.org/features/all-features/
 More info: https://launchpad.net/~oisf/+archive/suricata-beta
Press [ENTER] to continue or ctrl-c to cancel adding it

gpg: keyring `/tmp/tmpqk6Ubk/secring.gpg' created
gpg: keyring `/tmp/tmpqk6Ubk/pubring.gpg' created
gpg: requesting key 66EB736F from hkp server keyserver.ubuntu.com
gpg: /tmp/tmpqk6Ubk/trustdb.gpg: trustdb created
gpg: key 66EB736F: public key "Launchpad PPA for Peter Manev" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)
OK

$ sudo apt-get update
Now I was ready to install Suricata and Htp, a dependency.
$ sudo apt-get install suricata htp
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
  libhtp1 libnet1 libnetfilter-queue1 libnspr4 libnss3 libyaml-0-2
The following NEW packages will be installed:
  htp libhtp1 libnet1 libnetfilter-queue1 libnspr4 libnss3 libyaml-0-2
  suricata
0 upgraded, 8 newly installed, 0 to remove and 0 not upgraded.
Need to get 2,510 kB of archives.
After this operation, 8,394 kB of additional disk space will be used.
Do you want to continue [Y/n]?
...snip...
With this process done I added rules from Emerging Threats. I found Samiux's blog post helpful.
$ cd /etc/suricata
$ sudo wget https://rules.emergingthreatspro.com/open/suricata/emerging.rules.tar.gz
$ sudo tar -xzf emerging.rules.tar.gz
$ sudo mkdir /var/log/suricata
$ sudo touch /etc/suricata/threshold.config

Now I had to edit /etc/suricata/suricata.yaml. The following diff shows the changes I made to the original file.

$ diff -u /etc/suricata/suricata.yaml.orig /etc/suricata/suricata.yaml
--- /etc/suricata/suricata.yaml.orig    2014-01-25 21:39:57.542801685 -0500
+++ /etc/suricata/suricata.yaml 2014-01-25 21:41:31.530801055 -0500
@@ -46,7 +46,7 @@

 # Default pid file.
 # Will use this file if no --pidfile in command options.
-#pid-file: /var/run/suricata.pid
+pid-file: /var/run/suricata.pid

 # Daemon working directory
 # Suricata will change directory to this one if provided
@@ -208,7 +208,7 @@

   # a line based information for dropped packets in IPS mode
   - drop:
-      enabled: no
+      enabled: yes
       filename: drop.log
       append: yes
       #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram'
@@ -337,7 +337,7 @@

 # You can specify a threshold config file by setting "threshold-file"
 # to the path of the threshold config file:
-# threshold-file: /etc/suricata/threshold.config
+threshold-file: /etc/suricata/threshold.config

 # The detection engine builds internal groups of signatures. The engine
 # allow us to specify the profile to use for them, to manage memory on an
@@ -373,7 +373,7 @@
   - inspection-recursion-limit: 3000
   # When rule-reload is enabled, sending a USR2 signal to the Suricata process
   # will trigger a live rule reload. Experimental feature, use with care.
-  #- rule-reload: true
+  - rule-reload: true
   # If set to yes, the loading of signatures will be made after the capture
   # is started. This will limit the downtime in IPS mode.
   #- delayed-detect: yes
Next I added the following test rule to /etc/suricata/rules/drop.rules. The file location is arbitrary. I wrote a simple rule to alert on ICMP traffic from a test system, 192.168.2.126. All of the following is one line. I just broke it for readability.
alert icmp 192.168.2.126 any -> any any (msg:"ALERT test ICMP ping from 192.168.2.106";
 icode:0; itype:8; classtype:trojan-activity; sid:99999998; rev:1;)

Notice I have no iptables rules loaded at this point:

$ sudo iptables -vnL
Chain INPUT (policy ACCEPT 5 packets, 392 bytes)
 pkts bytes target     prot opt in     out     source               destination 

Chain FORWARD (policy ACCEPT 4 packets, 240 bytes)
 pkts bytes target     prot opt in     out     source               destination 

Chain OUTPUT (policy ACCEPT 4 packets, 496 bytes)
 pkts bytes target     prot opt in     out     source               destination

Now I was ready to see if Suricata would at least see and alert on traffic matching my ICMP test rule. First I started Suricata and told it to watch br0, the bridge interface.

$ sudo suricata -c /etc/suricata/suricata.yaml -i br0

25/1/2014 -- 22:44:13 -  - This is Suricata version 2.0beta2 RELEASE
25/1/2014 -- 22:44:16 -  - [ERRCODE: SC_ERR_NO_RULES(42)] - No rules loaded from /etc/suricata/rules/emerging-icmp.rules
25/1/2014 -- 22:44:33 -  - [ERRCODE: SC_ERR_OPENING_RULE_FILE(41)] - opening rule file /etc/suricata/rules/dns-events.rules: No such file or directory.
25/1/2014 -- 22:44:51 -  - [ERRCODE: SC_ERR_PCAP_CREATE(21)] - Using Pcap capture with GRO or LRO activated can lead to capture problems.
25/1/2014 -- 22:44:51 -  - all 2 packet processing threads, 3 management threads initialized, engine started.
I don't care about the Warning or Error notices here. I could fix those but they are not germane to demonstrating the main point of this post.

On a separate system, 192.168.2.126, I pinged 192.168.2.142.

$ ping -c 2 192.168.2.142
PING 192.168.2.142 (192.168.2.142) 56(84) bytes of data.
64 bytes from 192.168.2.142: icmp_req=1 ttl=64 time=5.29 ms
64 bytes from 192.168.2.142: icmp_req=2 ttl=64 time=4.03 ms

--- 192.168.2.142 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 4.030/4.663/5.297/0.637 ms
Then I checked my Suricata logs:
$ ls -al /var/log/suricata/
total 88
drwxr-xr-x  3 root root  4096 Jan 25 22:50 .
drwxr-xr-x 11 root root  4096 Jan 25 21:38 ..
-rw-r--r--  1 root root     0 Jan 25 22:15 drop.log
-rw-r--r--  1 root root   392 Jan 25 22:50 fast.log
-rw-r--r--  1 root root     0 Jan 25 21:42 http.log
-rw-r--r--  1 root root 66008 Jan 25 22:50 stats.log
drwxr-xr-x  2 root root  4096 Jan 25 22:15 .tmp
-rw-r--r--  1 root root   388 Jan 25 22:50 unified2.alert.1390708237

$ cat /var/log/suricata/fast.log
01/25/2014-22:50:40.510124  [**] [1:99999998:1] ALERT test ICMP ping from 192.168.2.106 [**] [Classification: A Network Trojan was detected] [Priority: 1] {ICMP} 192.168.2.126:8 -> 192.168.2.142:0
01/25/2014-22:50:41.510464  [**] [1:99999998:1] ALERT test ICMP ping from 192.168.2.106 [**] [Classification: A Network Trojan was detected] [Priority: 1] {ICMP} 192.168.2.126:8 -> 192.168.2.142:0
That worked as expected. I got alerts on the ICMP traffic matching the test ALERT rule.

Now it was time to drop traffic!

I added a new rule to drop.rules, again broken only for readability here:

drop icmp 192.168.2.126 any -> any any (msg:"DROP test ICMP ping from 192.168.2.106";
 icode:0; itype:8; classtype:trojan-activity; sid:99999999; rev:1;)
I also disabled the previous ALERT rule by commenting it out.

Next I added iptables rules for the FORWARD chain, for traffic traversing the bridge. This Documentation was helpful.

$ sudo iptables -I FORWARD -j NFQUEUE

$ sudo iptables -vnL
Chain INPUT (policy ACCEPT 32 packets, 2752 bytes)
 pkts bytes target     prot opt in     out     source               destination 

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination 
    0     0 NFQUEUE    all  --  *      *       0.0.0.0/0            0.0.0.0/0            NFQUEUE num 0

Chain OUTPUT (policy ACCEPT 25 packets, 2600 bytes)
 pkts bytes target     prot opt in     out     source               destination 
Finally I restarted Suricata, this time telling it to use queue 0, where NFQUEUE was waiting for packets for Suricata.
$ sudo suricata -c /etc/suricata/suricata.yaml -q 0
25/1/2014 -- 22:54:49 -  - This is Suricata version 2.0beta2 RELEASE
25/1/2014 -- 22:54:52 -  - [ERRCODE: SC_ERR_NO_RULES(42)] - No rules loaded from /etc/suricata/rules/emerging-icmp.rules
25/1/2014 -- 22:55:08 -  - [ERRCODE: SC_ERR_OPENING_RULE_FILE(41)] - opening rule file /etc/suricata/rules/dns-events.rules: No such file or directory.
25/1/2014 -- 22:55:26 -  - all 3 packet processing threads, 3 management threads initialized, engine started.
With Suricata running in IPS mode, I tried pinging 192.168.2.142 from 192.168.2.126 as I did earlier.
$ ping -c 2 192.168.2.142
PING 192.168.2.142 (192.168.2.142) 56(84) bytes of data.

--- 192.168.2.142 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1006ms
Nothing got through! I confirmed that I could ping the same box from another source IP address. In other words, only ICMP from 192.168.2.126 was blocked. Now check the Suricata logs:
$ ls -al /var/log/suricata/
total 152
drwxr-xr-x  3 root root   4096 Jan 25 22:57 .
drwxr-xr-x 11 root root   4096 Jan 25 21:38 ..
-rw-r--r--  1 root root    294 Jan 25 22:57 drop.log
-rw-r--r--  1 root root    798 Jan 25 22:57 fast.log
-rw-r--r--  1 root root      0 Jan 25 21:42 http.log
-rw-r--r--  1 root root 125812 Jan 25 22:57 stats.log
drwxr-xr-x  2 root root   4096 Jan 25 22:15 .tmp
-rw-r--r--  1 root root    388 Jan 25 22:50 unified2.alert.1390708237
-rw-r--r--  1 root root      0 Jan 25 22:55 unified2.alert.1390708526
-rw-r--r--  1 root root    360 Jan 25 22:57 unified2.alert.1390708633

$ cat drop.log
01/25/2014-22:57:17.031400: IN= OUT= SRC=192.168.2.126 DST=192.168.2.142 LEN=84 TOS=0x00 TTL=64 ID=36055 PROTO=ICMP TYPE=8 CODE=0 ID=59729 SEQ=256
01/25/2014-22:57:18.038179: IN= OUT= SRC=192.168.2.126 DST=192.168.2.142 LEN=84 TOS=0x00 TTL=64 ID=36056 PROTO=ICMP TYPE=8 CODE=0 ID=59729 SEQ=512
Cool, those are our dropped ICMP packets. Checking fast.log we'll see the original two ALERT test messages, but check out the new DROP test messages too:
$ cat /var/log/suricata/fast.log
01/25/2014-22:50:40.510124  [**] [1:99999998:1] ALERT test ICMP ping from 192.168.2.106 [**] [Classification: A Network Trojan was detected] [Priority: 1] {ICMP} 192.168.2.126:8 -> 192.168.2.142:0
01/25/2014-22:50:41.510464  [**] [1:99999998:1] ALERT test ICMP ping from 192.168.2.106 [**] [Classification: A Network Trojan was detected] [Priority: 1] {ICMP} 192.168.2.126:8 -> 192.168.2.142:0
01/25/2014-22:57:17.031400  [Drop] [**] [1:99999999:1] DROP test ICMP ping from 192.168.2.106 [**] [Classification: A Network Trojan was detected] [Priority: 1] {ICMP} 192.168.2.126:8 -> 192.168.2.142:0
01/25/2014-22:57:18.038179  [Drop] [**] [1:99999999:1] DROP test ICMP ping from 192.168.2.106 [**] [Classification: A Network Trojan was detected] [Priority: 1] {ICMP} 192.168.2.126:8 -> 192.168.2.142:0
So that's it.

Note that with this configuration, if you stop Suricata then the host it's "protecting" is totally unreachable. You can restore connectivity by flushing the iptables rules via this command:

$ sudo iptables -F
Now the endpoint is reachable while Suricata is not running. To re-enable the IPS, you have to set up the NFQUEUE via iptables again as shown previously.

Following these directions you have the foundation for building a bridged IPS using Suricata on Ubuntu Server 12.04. The next step would be to fix the configuration issues causing the start-up error messages, make the bridge, firewall, and Suricata components available at start-up, and then build your own set of DROP rules. There are probably also optimizations for PF_RING and other performance features. Good luck!

Do you run Suricata as an IPS? How do you do it? Have you tried the new 2.x beta?

2 comments:

Camere de supraveghere said...

There are probably also optimizations for PF_RING and other performance features.

Anonymous said...

Thank you for writing this doc. I'm also wanting to insert Suricata transparently in my network and this page lays it out nicely. Thanks again