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

26 March, 2012

Updating to Snort 2.9.2 and Barnyard2

After fixing hardware problems that had my home network sensor out of commission for the better part of a year, I recently got the system inline again. Because the sensor had been down for so long, I was running a fairly old version of Snort, 2.9.0.3, along with barnyard 0.2.0. I decided the first thing I should do after updating the OS itself was update Snort and Barnyard.

I won't go through the process in detail since there are many resources online for installing and configuring Snort. The main thing I will point out is that you should always look in the docs/ directory for information on installing and upgrading. If you're updating from a previous version, pay particular attention to changes and new features. Another important thing to do is look closely at the snort.conf provided with a given version in etc/ since it will have a lot of information on defaults and configuration directives that may be required. These won't always be the same as previous versions. It's also important to update to the latest rule sets, check for new rules files, and do all the other normal tuning to make sure certain rules are turned off or on.

I had two main problems when I updated, one with Snort and one with Barnyard2. Since Snort is the main piece of the puzzle here, I updated it prior to Barnyard. After updating to Snort-2.9.2.1 and fixing the configuration, I was able to run Snort successfully using the options I normally had previously. However, as soon as I put the sensor back inline and Snort started processing packets, Snort would exit with an error.

Can't acquire (-1) - ipq_daq_acquire: ipq_read=-1 error Failed to receive netlink message!

A quick search revealed that I had to remove the ip_queue module. JJ Cummings on the #snort channel pointed out to me that NFQ is the more recent option than IPQ. I am using Slackware-current, so even though it is a maintained distribution it is also not surprising that I was using an older option. Slackware also did not have a couple of the required libraries to compile DAQ with support for NFQ, so I went to Slackbuilds.org to get the files allowing me to create Slackware packages for libnetfilter_queue and libnfnetlink.

Once I got the new packages installed, made sure the ip_queue module wasn't loaded, recompiled DAQ to support NFQ, and changed my Snort init to use --daq nfq, my inline Snort was working once again.

Next, I updated from Barnyard-0.2.0.

$ barnyard2 -V

  ______   -*> Barnyard2 <*-
 / ,,_  \  Version 2.1.10-beta2 (Build 266) TCL
 |o"  )~|  By Ian Firns (SecurixLive): http://www.securixlive.com/
 + '''' +  (C) Copyright 2008-2011 Ian Firns


Barnyard2 is needed to process Snort's newer output mode, unified2. My snort.conf changed from:

output log_unified: filename unified.log, limit 128

to:

output unified2: filename unified.log, limit 128

When I got Barnyard2 up and running, it was obviously not successfully processing the unified2 files from Snort. Barnyard2 kept repeating the following error as it tried to process the files.

WARNING: No function defined to read header.

I found a thread on the snort-users list that indicated Barnyard2 was getting a file type it wasn't expecting, which made sense considering the warning message. This issue gave me more problems than it should have and I eventually realized it was because of an error in my barnyard.conf file. The input is supposed to read "input unified2" but I had somehow managed to include a colon after "input". Once I fixed that line, Barnyard2 started working, with alerts being properly processed and showing up in Sguil once again.

The next update will be to go from Sguil-0.7.0 to Sguil-0.8.0.

10 April, 2009

Upgrading to Snort 2.8.4

Hopefully, everyone running Snort has been paying attention and noticed that Snort 2.8.4 was released on 07 April and the corresponding new rule sets were released on 08 April. If you pay for Snort rules, the new netbios.rules will not work with Snort versions prior to 2.8.4, so you need to upgrade.

Upgrading was mostly painless just to get Snort running, though the dcerpc2 preprocessor settings definitely may require tweaking beyond the defaults. Generally, when I'm upgrading and there is something like a new preprocessor, I will start by getting Snort upgraded and successfully running with the defaults for the preprocessor, then will tune the settings as needed after I'm sure the new version is working.

The first thing to do after downloading and extracting is read the RELEASENOTES and also any applicable READMEs. Since the dcerpc2 preprocessor is new, the README.dcerpc2 may be of particular interest. A lot of people don't realize how much documentation is included.

$ wget http://www.snort.org/dl/snort-2.8.4.tar.gz
$ tar xzf snort-2.8.4.tar.gz
$ cd snort-2.8.4/doc
$ ls
AUTHORS README.alert_order README.ppm
BUGS README.asn1 README.sfportscan
CREDITS README.csv README.ssh
INSTALL README.database README.ssl
Makefile.am README.dcerpc README.stream5
Makefile.in README.dcerpc2 README.tag
NEWS README.decode* README.thresholding
PROBLEMS README.decoder_preproc_rules README.variables
README README.dns README.wireless
README.ARUBA README.event_queue TODO
README.FLEXRESP README.flowbits USAGE
README.FLEXRESP2 README.frag3 WISHLIST
README.INLINE README.ftptelnet faq.pdf
README.PLUGINS README.gre faq.tex
README.PerfProfiling README.http_inspect generators
README.SMTP README.ipip snort_manual.pdf
README.UNSOCK README.ipv6 snort_manual.tex
README.WIN32 README.pcap_readmode snort_schema_v106.pdf
The following is the default configuration as listed in the README.dcerpc2.
preprocessor dcerpc2_server: default, policy WinXP, \
detect [smb [139,445], tcp 135, udp 135, rpc-over-http-server 593], \
autodetect [tcp 1025:, udp 1025:, rpc-over-http-server 1025:], \
smb_max_chain 3
For some environments, it may be useful to turn off the preprocessor alerts or turn them off for specific systems.
preprocessor dcerpc2: memcap 102400, events none
Or:
preprocessor dcerpc2_server: default, policy WinXP, \
detect [smb [139,445], tcp 135, udp 135, rpc-over-http-server 593], \
autodetect [tcp 1025:, udp 1025:, rpc-over-http-server 1025:], \
smb_max_chain 3
preprocessor dcerpc2_server: net $SCANNERS, detect none
No matter what, the dcerpc configuration should be removed from the snort.conf and replaced with a dcerpc2 configuration for Snort 2.8.4.

After that, I'll configure and install Snort.
$  ./configure --enable-dynamicplugin --enable-inline --enable-perfprofiling
$ make
$ sudo /etc/rc.d/rc.snort-inline stop
$ sudo make install
$ which snort
/usr/local/bin/snort
$ snort -V

,,_ -*> Snort! <*-
o" )~ Version 2.8.4 (Build 26) inline
'''' By Martin Roesch & The Snort Team: http://www.snort.org/team.html
Copyright (C) 1998-2009 Sourcefire, Inc., et al.
Using PCRE version: 7.7 2008-05-07

$ sudo /etc/rc.d/rc.snort-inline start
Starting snort-inline
Initializing Inline mode
building cached socket reset packets
Although the old netbios.rules will still work with the new version, it's also time to update to the latest rules to take advantage of the smaller number of netbios.rules. Note that this only applies for subscription rules since the free ones won't reflect the changes for 30 days.

Some of the rules in the new netbios.rules file have SIDs that were unchanged, so I decided to re-enable any of those that I had previously disabled in my oinkmaster.conf. I can always disable them again, but with the new preprocessor and possible changes to the remaining SIDs, I decided it was best to reevaluate them.

Since I'm also using precompiled shared object rules, I also update from the ones compiled for 2.8.3.2 to the ones compiled for 2.8.4. I keep the rule stubs in a directory along with symlinks to the corresponding SO files, so I simply remove the symlink and recreate it to the new SO rules.
$ rm /etc/snort/so_rules/*so
$ ln -s /etc/snort/so_rules/precompiled/CentOS-5.0/i386/2.8.4/*so /etc/snort/so_rules/

12 February, 2009

Snort 2.8.4 has a new DCE/RPC preprocessor

According to the VRT blog, Snort 2.8.4 is going to have a new DCE/RPC 2 preprocessor. The README.dcerpc2 was not included in the first release candidate for 2.8.4, but a follow-up on the snort-users list included it. The README covers a lot of information, and is definitely useful to understand the changes and configuration options.

These changes look to be an improvement, but they also have the potential to cause a lot of work and heartache in the short term for Emerging Threats and Snort users. From the VRT blog:

This preprocessor handles all the decoding functions that were previously taken care of using rules and flowbits in a lot of those rules. The upshot is that the number of netbios rules released for any vulnerability that can be exploited over dcerpc is going to be reduced greatly. The number of netbios rules previously released is also going to be reduced in a similar manner.

The downside is that this functionality is only available in Snort 2.8.4 with the dcerpc2 preprocessor. There is no backwards compatibility. Also, a number of netbios rules will be deleted and replaced.
Snort users are going to have to make sure to properly configure the new version. I know from the snort-users mailing list that far too many people use old versions of Snort, so this causes them problems. Realistically, there is usually no reason to use older versions rather than the latest stable release.

Emerging Threats distributes quite a few NetBIOS rules, so I'm sure the new preprocessor will also have an effect on Emerging Threats rules. I seriously doubt that either VRT or Emerging Threats wants to maintain a set of rules for 2.8.4 and above, plus another set for older versions. If I'm interpreting Nigel's blog post correctly, it seems that VRT is going to force the issue by only issuing new and updated NetBIOS rules for 2.8.4 and above. Assuming the improvements in the preprocessor are as stated, I think that is the right choice, but lots of users are going to complain.

29 October, 2008

Snort shared object rules with Sguil

More and more Sourcefire VRT Snort rules are being released in the shared object (SO) rules format. As examples, Sourcefire released rules on 14 October that were designed to detect attacks targeting MS08-057, MS08-058, MS08-059, MS08-060, MS08-062, MS08-063 and MS08-065 vulnerabilities. On 23 October, Sourcefire released rules related to MS08-067, a vulnerability that has garnered a lot of attention.

It looks like all these recently released rules are SO rules. It is easy to tell a SO rule from a traditional Snort rule using the Generator ID, because SO rules use GID 3 while the old rule format uses GID 1.

Because Sourcefire is issuing all these rules in SO format, if you don't want to miss rules for recent vulnerabilities it is definitely important to test and implement the new format and keep the rules updated. When I implemented the rules in production, I used How to use shared object rules in Snort by Richard Bejtlich as a guide for adding shared object rules to Snort. It seems fairly complete and I was able to get the precompiled rules working on RHEL/CentOS.

Unfortunately, getting the rules working and updating them is not as simple and certainly not identical to updating rules that use the old format. Oinkmaster will edit the stub files to enable and disable the SO rules, but it requires running Oinkmaster a second time with a separate configuration file. From the Oinkmaster FAQ:

Q34: Can Oinkmaster update the shared object rules (so_rules)?

A34: Yes, but you have to run Oinkmaster separately with its own
configuration file. Copy your regular oinkmaster.conf file
to oinkmaster-so-rules.conf (or create a new one) and set
"rules_dir = so_rules". Then run Oinkmaster with
-C <path tooinkmaster-so-rules.conf> and use an output directory
(-o <dir>) different than your regular rules directory. This is
important as the "rules" and "so_rules" directories contains
files with identical filenames. See the Snort documentation on how
to use shared object rules. The shared object rules are currently
disabled by default so you have to use "enablesid" or "modifysid"
to activate the ones you want to use.
To update my rules, I first download the rules and run Oinkmaster to update my GID 1 rules. Then I extract the so_rules so I can run Snort with the '--dump-dynamic-rules' option. This will generate the required stub files, but they will not contain any changes you made to enable or disable specific rules. To change which are enabled or disabled, I run Oinkmaster again with the oinkmaster-so-rules.conf.

For Sguil to properly show the rule msg in the 'Event Message' column on the client, you must generate a new gen-msg.map file. David Bianco gave me a couple shell commands, one of which uses 'create-sidmap.pl' from the Oinkmaster contrib directory, to update the gen-msg.map file.
create-sidmap.pl ruledir/so_rules | perl -ne 'm/(\d+) \|\| ([^\|]+) \|\|/g; print "3 || $1 || $2\n";' > ruledir/so_rules/gen-msg.map

cat ruledir/gen-msg.map ruledir/so_rules/gen-msg.map | sort -n | uniq > ruledir/so_rules/gen-msg-merged.map
After you check that the new file is correct, it can be moved to overwrite the old gen-msg.map. The alert name will be found based on the GID and SID, so without the update you would only see the numerical GID and SID when viewing alerts in Sguil instead of the actual text of the alert message.

One last thing to do is get the "Show Rule" checkbox in Sguil to show the rule stub when viewing SO rules. A quick temporary fix is fairly simple. Either rename and place all the rule stub files in the directory on your sguild server with all the other rules, or use a symbolic link. Either way, you have to use alternate names since the SO rules stub files use the same naming scheme as the standard rule files.

Once that is done, it just requires a simple change to 'extdata.tcl' in the 'lib' directory of the Sguil client. Change the following line:
 if { $genID != "1" } {
to
 if { $genID != "1" && $genID != "3" } {
David Bianco pointed out that there is nothing to prevent SO rules and standard rules from sharing a SID since they have a different GID, so the above solution could get the wrong rule message if there are identical SIDs. He said he will probably add code to look in the ruledir for GID 1, and look in ruledir/so_rules for GID 3. This is definitely the better way and not too complicated, so hopefully Sguil CVS will have the code added in the near future.

29 August, 2008

Snort DNS preprocessor

Scott Campbell of NERSC posted to the snort-devel mailing list today about his DNS preprocessor that is designed to detect DNS cache poisoning and DNS fast flux. His write-up on both features looks interesting and I hope to play with the preprocessor on my lab setup. Note that he recommends not running this in production because it is an early beta.

For full details check his write-up, but the following quotes explain that the preprocessor is checking three basic conditions for DNS cache poisoning:

  • Multiple responses to a query where the DNS server IP and query name match, but the transaction ID varies.
  • Multiple responses to a query where the DNS server IP, query name and transaction ID match.
  • Unexpected responses where there is no observed question.
The explanation of fast flux detection is a little more involved, and he also mentions that it will detect sites that are designed to behave in a similar way as fast flux, for example ntp.pool.org and chat.freenode.net.

If I get the chance to play with the preprocessor, I will definitely document my experience.

23 May, 2008

Snort 2.8.1 changes and upgrading

Snort 2.8.1 has been out since April, so this post is a little late. I wanted to upgrade some Red Hat/CentOS systems from Snort 2.8.0.2 to 2.8.1. When I write RHEL or Red Hat, it will include CentOS since what is applies to one should apply to the other.

I quickly found that the upgrade on RHEL4 was not exactly straightforward because the version of pcre used on RHEL4 is pcre 4.5, which is years old. Snort 2.8.1 requires at least pcre 6.0. For reference, RHEL5 is using pcre 6.6.

PCRE Changes

I had assumed an upgrade from 2.8.0.2 to 2.8.1 was minor, but the pcre change indicated there were definitely significant changes between versions. A few of the pcre changes made it into the Snort ChangeLog, and there is more in the Snort manual. I also had a brief discussion about the pcre changes with a few SourceFire developers that work on Snort and some other highly technical Snort users.

The most significant changes seems to be adding limits to pcre matching to help prevent performance problems and denial of service through pcre overload. At regular expression compile time, there will be a maximum number of state changes that can be passed and on evaluation libpcre will only change states that many times. There is a global config option that sets the maximum number of state changes and the limit can also be disabled per regular expression if needed.

The related configuration options for snort.conf are pcre_match_limit:

Restricts the amount of backtracking a given PCRE option. For example, it will limit the number of nested repeats within a pattern. A value of -1 allows for unlimited PCRE, up to the PCRE library compiled limit (around 10 million). A value of 0 results in no PCRE evaluation. The snort default value is 1500.
and pcre_match_limit_recursion:
Restricts the amount of stack used by a given PCRE option. A value of -1 allows for unlimited PCRE, up to the PCRE library compiled limit (around 10 million). A value of 0 results in no PCRE evaluation. The snort default value is 1500. This option is only useful if the value is less than the pcre_match_limit
The main discussion between the SourceFire folks and everyone else was whether it was wise to have the limits turned on by default and where the default of 1500 came from. I think leaving the pcre limits on by default makes sense because those that don't fiddle much with the Snort configuration probably need the protection of the limits more than someone that would notice when Snort performance was suffering.

The argument against having the limits on by default is that it could make certain rules ineffective. By cutting short the pcre, the rule may not trigger on traffic that should cause a Snort alert. I suspect that not many rules will hit the default pcre limit.

Other Changes Included in Snort 2.8.1

From the release notes:
[*] New Additions
* Target-Based support to allow rules to use an attribute table
describing services running on various hosts on the network.
Eliminates reliance on port-based rules.

* Support for GRE encapsulation for both IPv4 & IPv6.

* Support for IP over IP tunneling for both IPv4 & IPv6.

* SSL preprocessor to allow ability to not inspect encrypted traffic.

* Ability to read mulitple PCAPs from the command line.
The SSL/TLS preprocessor helps performance by allowing Snort to ignore encrypted traffic rather than inspecting it. I haven't looked at the target-based support yet, but it definitely sounds interesting.

I also noticed something from 2007-12-10 in the ChangeLog:
 * configure.in:
Add check for Phil Woods pcap so that pcap stats are computed
correctly. Thanks to John Hally for bringing this to our
attention.
That should be good for those running Phil Wood's pcap who may not have been seeing accurate statistics about packet loss.

A last note of interest about Snort 2.8.1 is that it fixes a vulnerability related to improper reassembly of fragmented IP packets.

Upgrading

Upgrading on RHEL5 was pretty simple, but upgrading on RHEL4 required downloading the source RPM for the pcre included with RHEL5 and building a RPM for RHEL4.

First, I installed compilers and the rpm-build package and the RPM source package for pcre-6.6. (Note that I'm using CentOS4 in the example, but the procedures for Red Hat should be nearly identical except for URLs). Next I built the pcre-6.6 RPMs and installed both pcre and pcre-devel.
# up2date -i cpp gcc gcc-c++ rpm-build
# rpm -Uvh http://isoredirect.centos.org/centos/5/updates/SRPMS/pcre-6.6-2.el5_1.7.src.rpm
$ rpmbuild -bb /usr/src/redhat/SPECS/pcre.spec
# rpm -U /usr/src/redhat/RPMS/i386/pcre-*rpm
# rpm -q pcre pcre-devel
pcre-6.6-2.7
pcre-devel-6.6-2.7
Now I can configure, make and make install Snort as usual. The snort.conf file will also need to be updated to reflect new options like the SSL/TLS preprocessor and non-default pcre checks. Note that the README.ssl also recommends changes to the stream5 preprocessor based on the SSL configuration.
$ ./configure --enable-dynamicplugin --enable-stream4udp --enable-perfprofiling
$ make
# make install
If you are building on a production box instead of a development box, some would recommend removing the compilers afterwards.

Here is an example of a SSL/TLS and stream5 configuration using default ports. By adding the default SSL/TLS ports to stream5_tcp settings, you also have to enumerate the default stream5_tcp ports or they will not be included. I bolded the default SSL/TLS ports, and the rest are default stream5_tcp ports:
preprocessor stream5_global: track_tcp yes, track_udp yes, track_icmp yes
preprocessor stream5_tcp: policy first, ports both 21 23 25 42 53 80 \
110 111 135 136 137 139 143 443 445 465 513 563 636 \
989 992 993 994 995 1433 1521 3306
preprocessor stream5_udp
preprocessor stream5_icmp
preprocessor ssl: \
noinspect_encrypted
I have tested to make sure Snort runs with this configuration for these preprocessors, but don't just copy it without checking my work. It is simply an example after reading the related README documentation. Note that the Stream 5 TCP Policy Reassembly Ports output to your message log when starting Snort will be truncated after the first 20 ports but all the ports listed will be included by Stream 5.

21 March, 2008

Passive Tools

I love passive tools, what I like to think of as the "M" in NSM.

I recently posted about PADS. Sguil also uses p0f for operating system fingerprinting, and sancp for session-logging.

Even the IDS and packet-logging components of Sguil are passive. There are plenty of other good passive tools available.

You can learn a lot just by listening.

You can also run Snort inline and active, which goes a little beyond monitoring, for better or worse.

18 March, 2008

Using DJ Bernstein's daemontools

I use DJ Bernstein's daemontools to monitor Barnyard, making sure the barnyard process will restart if it dies for any reason. Barnyard is an output spooler for Snort and is probably the the least stable of all the software that is used when running Sguil. When Barnyard encounters errors and exits, it needs to be restarted.

Daemontools is useful because it will watch a process and restart it when needed. For anyone that has used other DJ Bernstein software like djbdns or qmail, you may also have used daemontools. I think daemontools has a reputation as difficult to install and configure, but I've used it on a number of systems with barnyard or djbdns without any major issues. (As for qmail, I prefer postfix).

Here is how I installed it, which only has one small change from the install instructions.

mkdir -p /package
chmod 1755 /package
tar xzvpf install/daemontools-0.76.tar.gz -C /package/
cd /package/admin/daemontools-0.76/
Before running the install script, note the "errno" section on DJ Bernstein's Unix portability notes. On Linux, since I'm installing from source I need to replace one line in the src/error.h file, as shown in this patch snippet.
-extern int errno;
+#include <errno.h>
After changing error.h, I can run the installer.
./package/install
I configure daemontools to work with barnyard.
mkdir /etc/barnyard
vim /etc/barnyard/run
The "run" file simply is a script that runs barnyard. For example, the contents of mine:
#!/bin/sh
exec /bin/barnyard -c /etc/snort/barnyard.conf -d /nsm -f unified.log \
-w /nsm/waldo.file -a /nsm/by_archive
Next, I link the new barnyard directory to make it a subdirectory of daemontool's service directory.
ln -s /etc/barnyard /service/barnyard
When installing, daemontools automatically adds this entry to /etc/inittab:
SV:123456:respawn:/command/svscanboot
svscanboot starts a svscan process that then starts a supervise process for each subdirectory, which in this case would only be the barnyard directory. I can have the inittab file re-parsed with telinit q after daemontools is installed rather than rebooting.

If the barnyard process dies, daemontools will automatically try and restart it based on the contents of the "run" file.

Now, even if I kill the barnyard process on purpose then it will be restarted automatically. If I need to manage the process, I can use the svc command. For instance, to send barnyard a HUP or a KILL:
svc -h /service/barnyard
svc -k /service/barnyard
To add another process for daemontools to manage, just create a directory, create a run file, then link the new directory to daemontools' service directory.
mkdir /etc/someprocess
vim /etc/someprocess/run
ln -s /etc/someprocess /service/someprocess

06 January, 2008

IDS/IPS placement on home network

A coworker was asking me about setting up Snort at home so he could get some experience breaking things.

I put together some very rough diagrams with Dia. These are just common and inexpensive solutions for running Snort at home, either in passive (IDS) or active (Inline) modes. These configurations are all inexpensive. At most, you require an extra hub or switch. The only one that doesn't require anything other than the network cards on the sensor is an external inline sensor.

The first is a common home network configuration. This is basically how mine was before I installed Snort.

The second diagram shows an external sensor. An advantage to this is that you see everything. A disadvantage is that you see everything. The management interface is inside the firewall while the bridging interfaces are outside the firewall. Seeing all the traffic isn't the only disadvantage. Some other disadvantages:

  • You can't see internal addresses to identify individual systems.
  • You need a higher performance system. This is not usually a problem on a residential service, but it should be noted that a lot more traffic will pass through system since it's not behind the firewall. You will see a ton of automated scanning and exploit attempts even if the traffic won't make it past the firewall.
Placing the sensor outside the firewall is reasonable if you want to find out just how much activity is happening on the external segment, but it can be really noisy and you lose inside visibility.

The third image is using an extra switch. In this example, you will see all traffic going through the firewall, as well as all broadcast traffic on the private network. You won't see unicast traffic between internal hosts, but you will be able to identify which host is associated with any given traffic that is seen. Bridging is enabled on the sensor and you can run Snort inline. This is my preferred configuration unless you have a lot of wireless traffic.

The fourth diagram shows how to run Snort passively. There are two basic options. The first is a hub that will broadcast all traffic to all ports. This can hurt performance depending on how busy the internal network is. The second is with an inexpensive switch that supports port mirroring. I haven't used it, but I've seen an inexpensive Dell switch referenced that supports port mirroring. Note that it only supports monitoring four ports (PDF) at a time. In this configuration, you can see all traffic on the local segment in addition to Internet traffic. If using a switch with a mirror, you will probably need a separate management interface. If using a hub, the management interface can also do the sniffing.

You could also use a hub between the modem and the firewall if you wanted to run an external passive sensor.

EDIT: Based on Victor's comment, I added one other diagram. Diagram five shows the firewall and Snort inline on the same system. Victor uses iptables to filter the traffic first, then traffic that passes through the firewall goes to Snort running inline. He has separate Snort processes for the DMZ and the LAN.

This configuration is slightly more complicated. There are exceptions, but the places I've worked in the past would not have considered using this type of configuration mainly because they were quite large and wanted off-the-shelf networking products rather than rolling their own firewalls or routers. It is still a useful and usable configuration to learn, and setting it up would provide a lot of valuable experience.

03 January, 2008

Keeping Snort configuration updated

One thing that needs attention when keeping Snort tuned is updating the configuration variables in snort.conf when changes are made to the network. I recently noticed an alert was firing on legitimate DNS traffic because a new mail server was not in $SMTP_SERVERS. It's easy enough to add the IP to the SMTP_SERVERS variable.

In some cases, you may want that variable to hold other ones. For instance, a big company like GE might have many different sites or logical networks. It may be useful to separate the SMTP servers logically in the Snort.conf if the sensor is going to see the traffic from more than one site:

var EAST_COAST_TV_SMTP [192.168.1.1, 192.168.1.2]
var MICROWAVE_PROGRAMMING_SMTP [192.168.2.1,192.168.2.2]
var SMTP_SERVERS [$EAST_COAST_TV_SMTP,$MICROWAVE_PROGRAMMING_SMTP]
Note that you need the EAST_COAST_TV_SMTP and MICROWAVE_PROGRAMMING_SMTP variables set before they are used in the SMTP_SERVERS variable.

16 November, 2007

Bleeding Edge Founder Steps Down

The founder of Bleeding Edge Threats, Matt Jonkman, has stepped down. I don't think this could be considered anything but bad news for the project. Apparently the project now belongs to Sensory Networks, the main sponsor of the last 12 months. I believe the rules are BSD licensed, so while they are currently free, who knows what will happen in the future.

I'm sure Matt Jonkman will continue to do some interesting things in the future, and it sounds like he hopes to share with the rest of us again.

01 November, 2007

Snort Performance and Memory Map Pcap on RHEL

I previously wrote about installing Phil Wood's memory map enabled libpcap as an academic exercise on my home network. As Victor Julien pointed out to me, Snort in inline mode will be using ip_queue rather than the libpcap interface to the kernel. However, I have actually been using mmap libpcap with Snort in IDS mode for quite a while to help reduce packet loss monitoring fairly high bandwidth connections. In testing, I have been able to consistently run Snort in IDS mode and a flow_depth of zero without packet loss on a link doing up to 80Mb/s. Admittedly, this is on pretty high end hardware but it is much better performance than Snort with the regular libpcap. By tuning Snort, like setting flow_depth to something more sensible than zero and disabling rules that are bad for performance, it is easy to see how Snort could be used to monitor even busier links.

There are other ways to increase Snort performance, too. One is using PF_RING. Richard Fifarek has a good write-up about setting up PF_RING with Red Hat Enterprise Linux 4. Maybe I'll get around to testing PF_RING under the same circumstances as I use mmap libpcap, but I'd love to see comments from those that have done it already. I have seen a few comparisons, but not recently. The documentation for PACKET_MMAP, which can be found in the Linux kernel source, has more to say about packet capture performance.

It's fine to use PACKET_MMAP to improve the performance of the capture process, but it isn't everything. At least, if you are capturing at high speeds (this is relative to the cpu speed), you should check if the device driver of your network interface card supports some sort of interrupt load mitigation or (even better) if it supports NAPI, also make sure it is enabled.
I haven't had a chance to play with NAPI yet, but for anyone that is interested there is a NAPI_HOWTO.txt, also in the documentation section of the Linux kernel source.

One last way to improve performance is to use an architecture-specific compiler when building Snort. Although I'm not sure about other architectures, using the Intel compiler for some Intel hardware was mentioned as one of the best ways to improve performance when someone asked a SourceFire employee at Shmoocon a couple years ago about improving Snort performance.

Installing the modified libpcap and reinstalling all the software that depends on it is fairly simple on RHEL. In this case, I'm using RHEL5. Before installing the new libpcap, I stopped any processes that depended on Red Hat's official libpcap package. I removed the official Red Hat libpcap package and any other RPMs that depended on it.
rpm -e libpcap tcpdump
Then I installed the new libpcap.
tar xvzf libpcap-0.9x.20070528.tar.gz
cd libpcap--0.9x.20070528
./configure
make
make install
Now I can go ahead and reinstall the other software using the new libpcap. Just for kicks, the following installs libnet so I can enable flex-resp support even though I don't consider flex-resp very useful in production. Better to just put the box inline if you really need to stop traffic. TCP resets or ICMP unreachable messages leave something to be desired.
cd /usr/src/Libnet-1.0.2a
./configure --prefix=/usr/local/libnet
make
make install

cd /usr/src/tcpdump-3.9.8/
make clean
./configure
make
make install
The following configure statement for Snort should work with 2.6.1.5 or 2.8.0, but I think the --enable-stream4udp is actually now a default for 2.8.0 while it was not for 2.6.x.x.
cd /usr/src/snort-2.8.0
make clean
./configure --without-mysql --without-postgresql --without-oracle
--without-odbc --enable-dynamicplugin --enable-flexresp --enable-stream4udp
--enable-perfprofiling --with-libnet-libraries=/usr/local/libnet/lib
--with-libnet-includes=/usr/local/libnet/include
make
make install
I'm using sancp for session data:
cd /usr/src/sancp-1.6.1/
make clean
make
./install.sh
Finally, I need to set PCAP_FRAMES to a value that the system can use. Finding the maximum can be trial and error, but here are some examples how to set it. One is to set it for each individual application at startup. For instance, sancp doesn't seem to like to use PCAP_FRAMES, so I put the following in the sancpd init script:
export PCAP_FRAMES=0
On the other hand, Snort in IDS mode or packet logging mode can benefit a lot from setting PCAP_FRAMES. For instance,
export PCAP_FRAMES=65535
As I said, it may take experimentation to find the maximum value or the value that results in the best performance. For something like tcpdump, you might want to create an alias something like:
alias tcpdump='PCAP_FRAMES=65535 tcpdump'

23 October, 2007

Upgrading to Snort 2.8.0

I finally upgraded my test sensor from Snort 2.6.1.5 to Snort 2.8.0. David Bianco mentioned some of the new features in his blog a couple of months ago, so I won't get into the differences. I am mainly documenting the things I had to do for the upgrade so I have a reference if needed at a future date.

The first thing I did was look through the documentation in the "docs" directory, reading some of the README files for the preprocessors. The README.variables file was of particular interest since Snort 2.8 allows port lists. I also looked at the snort.conf file in the "etc" directory of the source tree to see how it differed from my current configuration file.

Next, I made a copy of my snort.conf from 2.6.1.5 and edited it for the changes in 2.8.0. I changed the HTTP_PORTS variable to list a few other ports besides 80, including 8080 and 8000. The portvar variable was used in the examples of multiple HTTP_PORTS.

portvar HTTP_PORTS [80,8000,8080,8888]
Although I only run HTTP on port 80, the Snort web-client ruleset and a number of Bleeding rules use the $HTTP_PORTS variable to detect attacks against web clients like Internet Explorer, Mozilla Firefox, media players, and more. After that simple change, I configured and installed Snort.
./configure --enable-dynamicplugin --enable-inline --enable-perfprofiling
make
make install
After installing, I tried to start Snort. The first problem I encountered was with my stream5 configuration. I had previously been using the stream4 and the flow preprocessors, but when changing the configuration to use stream5 I had not removed the flow preprocessor configuration. Stream5 handles everything that used to be handled by the combination of flow and stream4, so I removed the flow configuration. I also had to add the stream5_udp and stream5_icmp options.

A check of the configure help will also show that --enable-dynamicplugin is the default with 2.8.0, so it should not actually be needed in the configuration command.

After fixing stream5, I tried again and had one more problem. I was getting the following errors:
Oct 23 19:18:52 sensor snort[3117]: /etc/snort/snort.conf(206) unknown dynamic preprocessor "ftp_telnet"
Oct 23 19:18:52 sensor snort[3117]: /etc/snort/snort.conf(210) unknown dynamic preprocessor "ftp_telnet_protocol"
Oct 23 19:18:52 sensor snort[3117]: /etc/snort/snort.conf(221) unknown dynamic preprocessor "ftp_telnet_protocol"
Oct 23 19:18:52 sensor snort[3117]: /etc/snort/snort.conf(226) unknown dynamic preprocessor "ftp_telnet_protocol"
Oct 23 19:18:52 sensor snort[3117]: /etc/snort/snort.conf(238) unknown dynamic preprocessor "smtp"
Oct 23 19:18:52 sensor snort[3117]: /etc/snort/snort.conf(307) unknown dynamic preprocessor "dcerpc"
Oct 23 19:18:52 sensor snort[3117]: /etc/snort/snort.conf(313) unknown dynamic preprocessor "dns"
Oct 23 19:18:52 sensor snort[3117]: FATAL ERROR: Misconfigured dynamic preprocessor(s)
This was pretty easy to fix. I just needed the proper path to the dynamic preprocessors.
dynamicpreprocessor directory /usr/local/lib/snort_dynamicpreprocessor/
After I fixed the snort.conf, the next try to start Snort 2.8.0 was successful. Now that I have it installed and running with very similar settings to 2.6.1.5, it's time to dig deeper into the differences and possibly test other configuration changes.

30 September, 2007

Running IDS Inline

When do you run IDS inline?

Although the idea of running an IDS inline to prevent attacks rather than just detect them is appealing, reality is harsh. There are a lot of problems running an IDS inline.

The first and most significant problem with running IDS inline is that most people don't adequately tune IDS. This is a problem whether you run inline or passive IDS. I get the feeling that the general management view towards IDS, perpetuated by marketing, is that you should be able to drop an IDS on the network and it is ready to go. This is far from the truth. Network monitoring requires tuning all involved systems and humans to analyze the information provided by the systems.

When I set up my first Snort deployment, I spent countless hours tuning and tweaking the configuration, rules, performance and more. Along the way, I added Sguil, which was useful both for more thorough analysis and more effective tuning based on those analyses. Even after all that, tuning is a daily requirement and never should stop.

Every time you update rules, you should tune. Every time the network changes, you may need to tune. Every time your IDS itself is updated, you may need to tune. Every time a new attack is discovered, you may need to tune. Tuning does not and should not end unless you want your network security monitoring to become less effective over time. I would be willing to bet that a majority of inline IDS don't come close to taking full advantage of blocking features because of a lack of tuning. Passive IDS suffers from the same problem, but the results can be even worse if an inline IDS starts blocking legitimate traffic.

Another problem, somewhat related to tuning, with running IDS inline is that rules are never perfect. Do you trust your enabled rules to be 100% perfect? If not, what percentage of alerts from a given rule must be accurate to make the rule acceptable in blocking mode? Even good rules will sometimes or often trigger on benign traffic.

For Snort, one of the most reliable rule sets are policy violations. Both VRT rules and Bleeding rules are extremely reliable when detecting policy violations with a minimal number of alerts triggered on unrelated network traffic. Spyware rules are similarly accurate.

Rules designed to detect more serious malicious activity are much less consistent. Most are simply not reliable enough to use in a mode that blocks the traffic the rule is designed to detect. That does not mean the rules are necessarily bad! Good rules still aren't perfect. This is one of many reasons why there will always be work for security analysts. IDS or other NSM systems are no substitute for the analysis that an experienced human can provide. They simply are tools to to be used by the analyst.

Last, don't forget that running anything inline can seriously impact the network. If my Snort process at home dies for some reason, I can survive without Internet access until I get it restarted. This isn't always the case for businesses, so consider whether your traffic should be going through a system that fails open if there are problems. Even at home I don't queue port 22 to snort_inline because I want to be able to SSH into the box from the Internet if there are problems.

The real question that has to be answered is whether the benefits of dropping traffic iare worth the risks of running inline.

14 September, 2007

Pulling IP Addresses and Ranges From a Snort Rule

In my previous post, I included a short Perl script to pull IP addresses from a Snort rule file. The problem with the script was that it simply stripped CIDR notation rather than expanding to all the included IP addresses. For instance, 10.0.0.0/28 would become 10.0.0.0. After a little searching, I found the Perl module NetAddr::IP that can be used to more easily manage and manipulate IP addresses and subnets. I also found an example of how to use the module for subnet expansion, among other things.

The following modification of my previous script will not only grab all the IP addresses from the snort rule, but also expand all CIDR addresses to the individual IP addresses in the CIDR range.

Edit: If you grabbed the script before September 16, then grab it again. While I was trying to make it look pretty, I must have inadvertently altered the substitution to remove the trailing CIDR notation. The current version is corrected.

#!/usr/bin/perl
#
# Script to pull IP address from Snort rules file
# by nr
# 2007-08-30
# 2007-09-14 Added CIDR expansion

# Set filenames
$rulefile = "/home/nr/bleeding-compromised.rules";
$ip_outfile = "iplist.txt";

# Open file to read
die "Can't open rulefile.\n" unless open RULEFILE, "<", "$rulefile";
# Open file to write
die "Can't open outfile.\n" unless open IPLIST, ">", "$ip_outfile";

# Put each rule from rules file into array
chomp(@rule = <RULEFILE>);

# For each rule
foreach $rule (@rule) {
# Match only rules with IP addresses so we don't get comments etc
# This string match does not check for validity of IP addresses
if ( $rule =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ ) {
# Remove everything before [ character
$rule =~ s/.*\[//g;
# Remove everything after ] character
$rule =~ s/\].*//g;
# Split the remaining data using the commas
# and put it into ip_address array
@ip_address = split /\,/, $rule;

# For each IP address in array
foreach $ip_address (@ip_address) {

# Match on slash
if ( $ip_address =~ /.*\/.*/ ) {

# Expand CIDR to all IP addresses in range modified from
# http://www.perlmonks.org/?displaytype=print;node_id=190497
use NetAddr::IP;
my $newip = new NetAddr::IP($ip_address);

# While less than broadcast address
while ( $newip < $newip->broadcast) {
# Strip trailing slash and netmask from IP
$temp_ip = $newip;
$temp_ip =~ s/\/.*//g;
print IPLIST "$temp_ip\n";
# Increment to next IP
$newip ++;
}
}
# For non-CIDR, simply print IP
else {
print IPLIST "$ip_address\n";
}
}
}
}

# Close filehandles
close RULEFILE;
close IPLIST;

One last note. If you prefer to pass the rule file name and output file to the script at the command line every time you run it, change the $rulefile and $ip_outfile variables to equal $ARGV[0] and $ARGV[1].

10 September, 2007

Querying Session Data Based on Snort Rule IPs

Sometimes Snort rules can contain useful information but are not practical to use in production. The Bleeding Snort rules recently added a set of rules to detect connection attempts to known compromised hosts. If you take a look at the rules, you'll see that it is essentially a large list of IP addresses that are known to be compromised.

When I first ran these rules on a Snort sensor, they definitely gave me some alerts requiring action. However, the performance of the sensor really suffered, particularly as the set of IP addresses grew. Since the rules were causing packet loss, I wanted to disable them.

I decided to write a script to grab the IP addresses from the Bleeding rule, then load the addresses into my database to compare with stored sancp data. If you are monitoring your network but not storing session data acquired with tools like sancp or argus, you should be. In my case, I am running Sguil, which uses sancp.

First, I had to write the script to grab the IP addresses. Since I just finished an introduction to Perl class in school and had many projects that required string matching, I figured that was the way to go. Since I'm a beginner, I would be more than happy if anyone can offer improvements to the following script. In particular, one thing I have not worked on yet is a method for expanding CIDR notation to individual IP addresses. The bleeding-compromised.rules do contain some networks in CIDR notation rather than just individual IP addresses, and for now the script simply strips the notation resulting in an incomplete IP list.

Edit: I posted an updated script that replaces the one in this post. I would suggest using the updated version rather than this one.

#!/usr/bin/perl
#
# Script to pull IP address from Snort rules file
# by nr
# 2007-08-30

# Set filenames
$rulefile = "/nsm/rules/bleeding-compromised.rules";
$ip_outfile = "iplist.txt";

# Print error unless successful open of file to read
die "Can't open rulefile.\n" unless open RULEFILE, "<", "$rulefile"; # Open file to write open IPLIST, ">", "$ip_outfile";

# Put each rule from rules file into array
chomp(@rule = <RULEFILE>);

# For each rule
foreach $rule (@rule) {
# Match only rules with IP addresses so we don't get comments etc
# This string match does not check for validity of IP addresses
if ( $rule =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ ) {
# Remove everything before [ character
$rule =~ s/.*\[//g;
# Remove everything after ] character
$rule =~ s/\].*//g;
# Split the remaining data using the commas
# and put it into ip_address array
@ip_address = split /\,/, $rule;

# For each IP address in array
foreach $ip_address (@ip_address) {
# Remove CIDR notation (means those IP ranges are missed - need to fix)
$ip_address =~ s/\/.*//g;
# Print to output file one IP per line
print IPLIST "$ip_address\n";
}
}
}

# Close filehandles
close RULEFILE;
close IPLIST;

Now I have a file called "iplist.txt" with the list of IP addresses, one per line. Next, I log into MySQL and load the list into a temporary database and table. The table really only needs one column of the CHAR or VARCHAR data type. (See the MySQL documentation for creating tables or databases).

LOAD DATA LOCAL INFILE '/home/nr/iplist.txt' INTO TABLE temp.ipaddr;

Then I have to convert the IP addresses to the INT data type using the INET_ATON function so they can be matched against my sancp session data. I created the table "sguildb.ipaddresses" for cases like this where I want to load external IP address and then run a query. The "temp.ipaddr" table has one column called "new_ip". The "sguildb.ipaddresses" table also has one column, but called "dst_ip".

INSERT INTO sguildb.ipaddresses SELECT INET_ATON(new_ip) FROM temp.ipaddr;

In MySQL 5.x, you can combine the previous two steps to add and convert the data in one step. I'm currently running 4.1, so I have not investigated the exact syntax.

Finally, I can query my sancp session data for connections going to any of the IP addresses in sguildb.ipaddresses, which are the IP addresses from the Snort rule.

SELECT sancp.sid,INET_NTOA(sancp.src_ip),sancp.src_port,INET_NTOA(sancp.dst_ip),
sancp.dst_port,sancp.start_time FROM sancp INNER JOIN ipaddresses ON
(sancp.dst_ip = ipaddresses.dst_ip) WHERE sancp.start_time >= DATE_SUB(UTC_DATE(),
INTERVAL 24 HOUR) AND sancp.dst_port = '80';

This query will return the sensor ID, source IP, source port, destination IP, destination port, and session start time from the sancp table wherever the sancp.dst_ip matches the ipaddresses.dst_ip where I stored the IP addresses from the Snort rule. Notice that it will query the last 24 hours for port 80 connections only. Depending on the type of activity you are looking for, you could change ports or remove the port match entirely.

This whole process could be automated further by running the mysql commands directly from the Perl script so the compromised IP addresses are updated in the database when the script is run.

The final SQL query to match the compromised IP addresses with sancp destination IP addresses can easily be turned into a cronjob. For instance, if querying for the past 24 hours then run the cronjob once a day. Once the results are returned, if running Sguil with full content logging it is easy to then query for the individual connections you're interested in and view the ASCII transcripts or the packet captures.

08 September, 2007

Transparent Bridging, MMAP pcap, and Snort Inline

I use Snort and the Sguil Analyst Console for NSM, but there is always room to experiment and/or improve. Up to this point, I have used Snort either on mirrored (SPAN) ports or with a network TAP, both common configurations. After finally getting a second-hand CPU and motherboard to replace a dead CPU, I had a spare system to set up Snort inline at home.

The upgrade from Snort 2.4.x to 2.6.x.x was quite taxing on performance, so I decided it was also time to play with Phil Wood's MMAPped libpcap. The modified libpcap will make drastically fewer system calls when compared to the standard libpcap sniffing on a busy network. Although my home network certainly isn't high bandwidth, I wanted the experience of setting up Snort with the Phil Wood's modified version of libpcap. Since I actually did all this many months ago and am just now posting about it, I can say that I have seen a huge performance improvement when going from the standard libpcap to Phil Wood's libpcap in high bandwidth environments.

How would I implement Snort Inline on a home network? The two choices were to replace one of my routers with a BSD or Linux system configured as a router, or to set up Linux as a transparent bridge. For those that prefer FreeBSD, you would have to configure it as a router since the bridge code in FreeBSD does not support the ipfw divert socket. I am not familiar enough with other BSD versions to say whether their bridge code is the same or not.

I much preferred a bridge rather than a router since it would avoid the time-consuming process of reconfiguring my network topology. This meant that I had to use Linux, and my distribution in this case is Slackware-current. The process should not be much different for any distribution.

Installing Software

Because plugging in an untested bridge between my LAN and the Internet could interrupt my connection, I decided it would be easiest to get and install all the software prior to configuring the bridge and putting it inline.

My first step was to install the modified libpcap, which needs either flex and bison, or yacc. This was essentially a freshly built Slackware system and I didn't have them installed, so I used swaret to install the packages.

swaret --install flex
swaret --install bison
I was now ready to install libpcap.
cd /usr/src/
wget http://public.lanl.gov/cpw/libpcap-current.tar.gz
tar xvzf libpcap-current.tar.gz
ln -s libpcap-0.9.20060417 libpcap
cd libpcap
./configure
make
make install
Snort will need the header files from libpcap and the install did not copy them anywhere, so I manually copied the files to /usr/include/. Another option would be to create a link to the files in the include directory.
cp /usr/src/libpcap/pcap.h /usr/include/
cp /usr/src/libpcap/pcap-bpf.h /usr/include/
cp /usr/src/libpcap/pcap-namedb.h /usr/include/
Because this is a modified libpcap, all the software that depends on libpcap must also be compiled against the version I just installed. I will definitely be using tcpdump when I test the bridge.
wget http://www.tcpdump.org/daily/tcpdump-current.tar.gz
tar xvzf tcpdump-current.tar.gz
ln -s tcpdump-2007.01.07 tcpdump
cd tcpdump
./configure
make
make install
Now I could test that tcpdump worked with the PCAP_FRAMES option available because of the modified libpcap. For some reason, perhaps because of my kernel version, PCAP_FRAMES=max did not work but I was able to use it by manually setting the value. I was able to bump the value of PCAP_FRAMES quite high, above 300000, before it resulted in errors. I have yet to determine what that really means for performance. Here are two commands I used to show that the newly installed tcpdump worked with the modified libpcap.
PCAP_FRAMES=65535 PCAP_VERBOSE=1 PCAP_TO_MS=0 PCAP_PERIOD=10000 /usr/local/sbin/tcpdump \
-i eth0 -s 1514 -w /dev/null -c 100

PCAP_FRAMES=65535 /usr/local/sbin/tcpdump -v -i eth0
Snort needs libnet-1.0.2a when configured with --enable-inline, so I had to install libnet first.
tar xvzf libnet-1.0.2a
cd libnet-1.0.2a
./configure
make
make install
Finally, install Snort 2.6.x.x. (Note: Since this document was written quite a while ago, there are quite a few newer versions of Snort available). Another alternative to using the --enable-inline option with mainline Snort is to download snort_inline, which is maintained by William Metcalf and Victor Julien. There are a number of added features and conveniences when using snort_inline, as highlighted on Victor's blog. However, I used mainline Snort in the following example.
tar xvzf snort-2.6.1.2.tar.gz
cd snort-2.6.1.2
./configure --enable-dynamicplugin --enable-inline
make
make install
I tested snort with -V to check that it would start and was compiled to work inline. It shows that Snort was configured with the inline option.
snort -V

,,_ -*> Snort! <*-
o" )~ Version 2.6.1.2 (Build 34) inline
'''' By Martin Roesch & The Snort Team: http://www.snort.org/team.html
(C) Copyright 1998-2006 Sourcefire Inc., et al.

Configuring Linux for Transparent Bridging

Configuring the bridging is fairly simple. The only module I had to manually insert was ip_queue. Other modules that may be needed are ip_tables, iptable_filter and bridge.

In this case, eth0 is my separate management interface, I named the bridge interface bridge0, and the physical interfaces joining bridge0 were eth1 and eth2. The bridge device can be configured with an IP address if you do not want to use a separate NIC for management. In either case, make sure to secure the management NIC on your Snort box, for example limiting connections to the management IP so only source IP addresses in your private IP space are allowed to connect. Here, I created the bridge interface, added eth1 and eth2 to it, and brought them up:
/sbin/brctl addbr bridge0
/sbin/brctl addif bridge0 eth1
/sbin/brctl addif bridge0 eth2
/sbin/ifconfig eth1 up
/sbin/ifconfig eth2 up
/sbin/ifconfig bridge0 up
After some iptables configuration, bridge0 should work. Assuming the system is dedicated to being a bridge running Snort Inline, the only addition necessary to make bridging work is the following:
iptables -I FORWARD -o bridge0 -j ACCEPT
Now bridge0 should be ready to pass packets.

Once the bridge is connected, iptables can be used to show packet statistics and confirm that the bridge is forwarding. You can also use tcpdump -v -i bridge0 to confirm that traffic is passing if you skip ahead to installing libpcap and tcpdump prior to plugging in the bridge.
iptables -vL
--snip--
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
527 168K ACCEPT all -- any bridge0 anywhere anywhere
--snip--
The bridge is seeing packets! tcpdump showed that they were more than just broadcast packets as I accessed the Internet through the bridge.
PCAP_FRAMES=65535 /usr/local/sbin/tcpdump -v -i bridge0
tcpdump: WARNING: bridge0: no IPv4 address assigned
tcpdump: listening on bridge0, link-type EN10MB (Ethernet), capture
--snip--
57 packets captured
57 packets received by filter
0 packets dropped by kernel

Testing Snort Inline

Finally, I'm ready to configure and test Snort Inline. I am not going to cover Snort configuration, but I did write one test rule to put in local.rules and disabled all the other rule sets in snort.conf. The following rule should drop any outbound connection on the HTTP_PORT set in snort.conf.
drop tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"Test rule outbound HTTP"; \
classtype:misc-activity; sid: 3000000;)
Now I run Snort. The -v will print packets to the console so I can confirm that snort is seeing the traffic and the -Q tells snort to accept input from the iptables queue.
/usr/local/bin/snort -Qvc /etc/snort/snort.conf -l /data
Note that I forgot to add the PCAP_FRAMES value. In production on a busy network, I would add it permanently to my environmental variables and/or to my init scripts for Snort so it would always take advantage of Phil Wood's libpcap.

I add the necessary rule to iptables. I don't want to risk losing all connections by queueing everything, so I just queue port 80. This is what the line in my iptables-save file looks like:
-A FORWARD -i bridge0 -p tcp -m tcp --dport 80 -m state --state NEW -j QUEUE
I try to browse to a web site and get the following alert in /data/alert:
[**] [1:300000:0] Test rule outbound HTTP [**]
[Classification: Misc activity] [Priority: 3]
01/11-22:22:24.458394 xx.xx.xx.xx:60813 -> 66.35.250.209:80
TCP TTL:63 TOS:0x0 ID:52831 IpLen:20 DgmLen:60 DF
******S* Seq: 0xE79DA525 Ack: 0x0 Win: 0x16D0 TcpLen: 40
TCP Options (5) => MSS: 1460 SackOK TS: 604992578 0 NOP WS: 2
Everything is working. Now I have to get everything ready for production by fully configuring and tuning Snort. Once that is done, I will queue all traffic except port 22. Queuing port 22 could result in not being able to connect using SSH if the Snort process were to die or had to be restarted. If snort-inline is not running, all queued traffic is effectively dropped since Snort is required to pass the traffic from the queue back to iptables.