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:
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.)