Testing Your Snort Rules Redux

Exactly four years ago, I blogged about testing Snort rules on OpenBSD. That post described a quick way to test if Snort has correctly loaded your rules and whether it will emit an alert when it reads a matching packet.

But things have changed since then; for starters, the Snort rules I suggested in that post have been disabled in the official Snort ruleset for a long time now, so the instructions I wrote no longer work as-is.

That post also suggested the installation of an ancient webserver called thttpd, which has been removed (for a very good reason!) from the OpenBSD ports tree.

A new version of that blog post is sorely needed, so here it is!

One note before we begin: While this post talks about testing Snort on OpenBSD (specifically OpenBSD 6.0-current), the principles discussed here can be applied to testing Snort on other operating systems like Linux. I highly recommend OpenBSD though. :)

Test goals

Just like the earlier post, the goals of the test are to:

  • Confirm that you have actually loaded some rules
  • Ensure that your Snort setup can actually trigger alerts
  • Confirm that you are logging alerts to the right file

Note that this is just a simple test – we’re simply trying to confirm the above instead of doing a thorough test against a Snort installation. After all, it would be unwise to attempt a full all-out assault against Snort without confirming the above!

We will do this simple test by setting up two hosts: the Snort host and an “attacker” host. The Snort host will run snort and httpd (OpenBSD’s new webserver; more on that below!), while the attacker host will generate a “malicious” HTTP request that will match one of the rules on the Snort host and trigger an alert.

Here’s how it looks like graphically:

A simple Snort testbed

Note the sample IP addresses because we’ll be referring to them below.

Now that you have admired my MoMA-worthy artistic creation, it’s time to move on to installing Snort!

Installing Snort

Installing Snort is really easy on OpenBSD:

pkg_add snort

The pkg_add command will pull in dependent packages just like you expect it to.

Fetching Snort rules

Next, we grab some Snort rules to test. The steps here differ depending on whether you have signed up for an oinkcode at Snort.org or not.

For those unfamiliar with what an oinkcode is, it’s basically a registration code that lets you fetch registered Snort rules from Snort.org. There are two types of free rulesets at Snort.org:

  • A registered ruleset that needs the oinkcode; and
  • A community ruleset that does not need the oinkcode

Note that the registered ruleset also contains all the rules in the community ruleset. The good news is the test rule that I will use in this blog post is a community rule so it’s available in both rulesets. So it’s up to you whether you would like to sign up for an oinkcode or not.

If you’re serious about learning and using Snort though, I recommend signing up for the oinkcode.

Fetching test Snort rules with an oinkcode

If you have signed up for an oinkcode, simply read /usr/local/share/doc/pkg-readmes/snort-2.x.x.x for the steps to activate those rules. To summarize, here are the steps (assuming you’re running Snort 2.9.8.3, the latest version at the time of writing):

ftp -o snortrules-snapshot-2983.tar.gz \
    https://www.snort.org/reg-rules/snortrules-snapshot-2983.tar.gz/<oinkcode>
tar -C /etc/snort -xzf snortrules-snapshot-2983.tar.gz rules preproc_rules

Fetching test Snort rules without an oinkcode

If you have NOT signed up for an oinkcode, fetch the community ruleset using these commands:

ftp https://www.snort.org/downloads/community/community-rules.tar.gz
tar -C /etc/snort -s '/community-//' -xzf community-rules.tar.gz

You now have to edit /etc/snort/snort.conf and comment out all the include $RULE_PATH/*.rules lines (since they are meant for the registered ruleset) by adding a # character in front of those lines.

Now activate the community ruleset by adding this line:

include $RULE_PATH/community.rules

Starting Snort

Before starting Snort, check if you’re running Snort on a system with multiple network interfaces. If you are, you’ll need to specify the network interface you want Snort to listen on.

The best way to do this is to edit /etc/snort/snort.conf and add a line like this (for example, to make Snort listen on the em0 interface):

config interface: em0

Now let’s fire up Snort!

/etc/rc.d/snort start

Start the webserver

Now we start the webserver. As mentioned earlier, the good news is OpenBSD now comes with its own HTTP server called httpd, which makes it really straightforward to get an OpenBSD box to serve HTTP without installing any packages.

First, create a simple /etc/httpd.conf file:

ext_addr="*"

server "default" {
        listen on $ext_addr port 80
}

That’s crazy simple, right?

Then start httpd:

/etc/rc.d/httpd -f start

You’ll need -f to force httpd to start because the line httpd_flags=NO is in your /etc/rc.conf by default. If you wish to start httpd on a permanent basis (i.e. for it to persist across reboots), change that line in /etc/rc.conf to:

httpd_flags=

For more information on httpd, read up the man pages for httpd(8) and httpd.conf(5).

Triggering an alert

We’re finally at the fun part!

To get Snort to trigger an alert, you’ll need to look for a rule that allows you to create a packet that would trigger an alert from it. The easiest way is to look for simple HTTP-based rules:

grep -v '# alert' /etc/snort/rules/*.rules | \
    grep '> \$HOME_NET \$HTTP_PORTS' | less

Fortunately I’ve done this for you, and found this simple one in blacklist.rules:

alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS
(msg:"BLACKLIST User-Agent ASafaWeb Scan"; flow:to_server,established;
content:"User-Agent|3A| asafaweb.com"; fast_pattern:only; http_header;
metadata:policy balanced-ips alert, policy security-ips drop,
ruleset community, service http; reference:url,asafaweb.com;
classtype:network-scan; sid:21327; rev:6;)

Now on the Snort host, run this to watch its alert log file:

tail -f /var/snort/log/alert

If your attacker host is also an OpenBSD system, you can use OpenBSD’s ftp(1) command to generate the HTTP request (remember to replace the IP address below with the IP of your Snort host):

ftp -U 'asafaweb.com' http://172.16.10.8/index.html

If your attacker host is not an OpenBSD system, you could use curl or wget:

curl -A 'asafaweb.com' http://172.16.10.8/index.html
wget -U 'asafaweb.com' http://172.16.10.8/index.html

The following alert should show up in your tail session on the Snort host:

[**] [1:21327:6] BLACKLIST User-Agent ASafaWeb Scan [**]
[Classification: Detection of a Network Scan] [Priority: 3]
09/29-23:36:38.000142 172.16.10.3:52234 -> 172.16.10.8:80
TCP TTL:64 TOS:0x0 ID:63384 IpLen:20 DgmLen:128 DF
***AP*** Seq: 0x2E060816  Ack: 0x53AAAF16  Win: 0x43C0  TcpLen: 32
[Xref => http://asafaweb.com]

Congratulations! You have successfully confirmed that Snort has loaded its rules and triggered an alert in the correct log file. Time to celebrate with a nice cup of coffee.

Next steps

This post just describes a simple way to test a Snort rule. If you want to fetch your Snort rules and manage them in a proper production environment, I recommend using PulledPork. This post from the Snort blog post describes why using PulledPork is important.

For further information on setting up Snort, check out:

Happy testing! (I would have said “Happy Snorting” but that felt a little weird.)