Snort and Base and Swatch on OS X Lion Server with PostgreSQL
I've installed the snort network intrusion prevention and detection system (IDS/IPS) on my OS X Lion Server along with BASE (web db interface) and Swatch (simple watchdog that emails alerts). Lion Server has moved to PostgreSQL as Apple's db chpoice, and this setup uses postgres for everything. I'm posting my notes here in case they're useful to others -- most of these notes are taken by copying what others have done and posted elsewhere, though there are many Lion-specific steps here. Please chime in with corrections and comments, especially about any security issues.
Some relevant websites for background and hints (with focus on MySQL installations, other BSD implementations):
- EN DAQ 0.6.1 and Snort 2.9.1 with Rules for Lion
- Simple WATCHdog 3.2.3_for_Lion
- Detect Network Intrusions with Snort/BASE
- Perfect Setup Of Snort + Base + PostgreSQL On Ubuntu 6.06 LTS
- Using PostgreSQL in Lion Server
Preliminaries
I'm assuming you've installed Xcode and MacPorts for Lion. I use vi to edit, others prefer nano or emacs. Your choice.
Snort
# Build snort
# Do NOT use macports snort, but DO use snort's dependencies from macports
$ sudo port install daq libdnet
$ curl -O -L http://www.snort.org/dl/snort-current/snort-2.9.1.tar.gz
$ curl -O -L http://www.snort.org/dl/snort-current/snort-2.9.1.tar.gz.sig
$ gpg --verify snort-2.9.1.tar.gz.sig snort-2.9.1.tar.gz
$ tar xzfvp ./snort-2.9.1.tar.gz
$ cd snort-2.9.1
$ ./configure --enable-ipv6 --enable-zlib --enable-gre --enable-mpls --enable-targetbased --enable-decoder-preprocessor-rules --enable-ppm --enable-perfprofiling --enable-inline-init-failopen --enable-pthread --enable-ppm-test --enable-sourcefire --enable-active-response --enable-normalizer --enable-reload --enable-reload-error-restart --enable-paf --enable-react --enable-flexresp3 --enable-aruba --with-postgresql
$ make && sudo make install
# Use latest rules from snort.org
# Register at snort.org and download latest ruleset: snortrules-snapshot-2910.tar.gz, snortrules-snapshot-2910.tar.gz.md5.txt
$ openssl md5 snortrules-snapshot-2910.tar.gz
$ more snortrules-snapshot-2910.tar.gz.md5.txt
$ tar -xzvf snortrules-snapshot-2910.tar.gz
$ sudo mv ./etc /etc/snort
$ sudo mv ./preproc_rules /etc/snort/preproc_rules
$ sudo mv ./rules /etc/snort/rules
$ sudo mv ./so_rules /etc/snort/so_rules
$ sudo chown -R root:wheel /etc/snort
# Modify snort.conf and syslog.conf
$ sudo vi /etc/snort/snort.conf
var RULE_PATH /etc/snort/rules
var SO_RULE_PATH /etc/snort/so_rules
var PREPROC_RULE_PATH /etc/snort/preproc_rules
output alert_syslog: LOG_LOCAL5 LOG_ALERT
$ sudo vi /etc/syslog.conf
# Insert this line
local5.* /var/log/snort/alert
$ sudo touch /etc/snort/rules/white_list.rules
$ sudo touch /etc/snort/rules/black_list.rules
$ sudo mkdir /usr/local/lib/snort_dynamicrules
# Create org.snort.Snort.plist
$ sudo vi /Library/LaunchDaemons/org.snort.Snort.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.snort.Snort</string>
<key>KeepAlive</key>
<true/>
<key>RunAtLoad</key>
<true/>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/snort</string>
<string>-D</string>
<string>-d</string>
<string>-e</string>
<string>-i</string>
<string>en0</string>
<string>-c</string>
<string>/etc/snort/snort.conf</string>
</array>
<key>ServiceDescription</key>
<string>Snort Ethernet</string>
</dict>
</plist>
# Create snort user. The intention is to let user snort have access only to the snort database.
$ sudo createuser -U _postgres -P snort
Password:
Enter password for new role:
Enter it again:
Shall the new role be a superuser? (y/n) n
Shall the new role be allowed to create databases? (y/n) n
Shall the new role be allowed to create more new roles? (y/n) n
# Create snort PostgreSQL database owned by user snort and has all owner privileges for to-be-created database snort
$ sudo createdb -U _postgres -O snort -W snort
$ cd /usr/local/pgsql
$ sudo psql -U snort snort < ./create_postgresql
# To clean up tests, errors: $ sudo serveradmin stop postgres ; sudo serveradmin start postgres ; sudo dropdb -U _postgres snort
# inspect snort PostgreSQL database
$ sudo psql -q -d snort snort --password
snort=# \d
# check the tables, indices, privileges, etc.
$ sudo psql -q -d snort _postgres --password
snort=# \dt
snort=# \dp
# Edit /etc/snort/snort.conf
$ sudo vi /etc/snort/snort.conf
output database: log, postgresql, user=snort password=password dbname=snort host=localhost
# Adjust postgresl configuration to allow for network connections: edit postgresql.conf and ph_hda.conf.
# On OS X Lion:
$ sudo vi /System/Library/LaunchDaemons/org.postgresql.postgres.plist
# Comment out XML lines that configure "-c listen_address=" in the command line:
<!-- Comment out "-c listen_addresses=", i.e. allow network connections on localhost
-- Confirm that /var/pgsql/postgresql.conf has default "# listen_addresses = 'localhost'"
<string>-c</string>
<string>listen_addresses=</string>
-->
$ sudo vi /var/pgsql/postgresql.conf
# listen_addresses = 'localhost'
$ sudo vi /var/pgsql/pg_hba.conf
# add line
host snort snort snort-sensor-host-ip/32 password
# Restart postgresql on OS X Lion Server
$ sudo serveradmin status postgres
$ sudo serveradmin stop postgres
$ sudo serveradmin start postgres
$ less /Library/Logs/PostgreSQL.log
$ ps -ef | grep postgres | grep -v grep
$ nmap -p 5432 localhost
Starting Nmap 5.51 ( http://nmap.org ) at 2011-10-09 06:10 EDT
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00024s latency).
PORT STATE SERVICE
5432/tcp open postgresql
# Sanity check that snort can connect to the database with non-daemon call
$ sudo /usr/local/bin/snort -d -e -i en0 -c /etc/snort/snort.conf
# Success looks like:
database: compiled support for (postgresql)
database: configured to use postgresql
database: schema version = 107
database: host = localhost
database: user = _postgres
database: database name = snort
database: sensor name = 16.2.0.0
database: sensor id = 1
database: data encoding = hex
database: detail level = full
database: ignore_bpf = no
database: using the "log" facility
database: compiled support for (postgresql)
database: configured to use postgresql
database: schema version = 107
database: host = localhost
database: user = snort
database: database name = snort
database: sensor name = 16.2.0.0
database: sensor id = 1
database: data encoding = hex
database: detail level = full
database: ignore_bpf = no
database: using the "log" facility
--== Initialization Complete ==--
,,_ -*> Snort! <*-
o" )~ Version 2.9.1 IPv6 GRE (Build 71)
'''' By Martin Roesch & The Snort Team: http://www.snort.org/snort/snort-team
Copyright (C) 1998-2011 Sourcefire, Inc., et al.
Using libpcap version 1.1.1
Using PCRE version: 8.12 2011-01-15
Using ZLIB version: 1.2.5
# Start snort using launchctl as below after adding the BASE schema to the snort database
Base
# use macports base
$ sudo port install base
# Add base schema to database snort
$ cd /opt/local/share/base/sql
$ sudo psql -U snort snort < ./create_base_tbls_pgsql.sql
# edit
$ cd /opt/local/share/base
$ sudo cp base_conf.php.dist base_conf.php
$ sudo vi base_conf.php
# Add/edit these lines
$BASE_urlpath = '/base';
$DBlib_path = '/opt/local/share/adodb5';
$DBtype = 'postgres';
$alert_dbname = 'snort';
$alert_host = 'localhost';
$alert_port = '';
$alert_user = 'snort';
$alert_password = 'snort_password';
$archive_exists = 1; # Set this to 1 if you have an archive DB
$archive_dbname = 'snort';
$archive_host = 'localhost';
$archive_port = '';
$archive_user = 'snort';
$archive_password = 'snort_password';
# Launch (load) / Kill (unload) snort
$ sudo launchctl load -w /Library/LaunchDaemons/org.snort.Snort.plist
# Tweak snort to ignore false alarms (after a day or so of collecting stats)
# threshold.conf: add these lines to end
# See http://taosecurity.blogspot.com/2006/08/more-snort-and-sguil-tuning.html
# How to find an sid: $ grep "Reset" /etc/snort/*.map
# Confirm at http://snortid.com/, e.g.
threshold gen_id 1, sig_id 129, type limit, track by_src, count 1, seconds 30
Swatch
# This will email high priority alerts to, e.g. admin@your.webserver.com
# http://www.mac.ph/www.mac.ph/Blog/Eintr%C3%A4ge/2011/8/26_Simple_WATCHdog_3.2.3_ f%C3%BCr_Lion.html
$ cd ~/Downloads
$ curl -L http://sourceforge.net/projects/swatch/files/swatch/3.2.3/swatch-3.2.3.tar.gz/do wnload?use_mirror -o swatch-3.2.3.tar.gz
$ tar xzfvp ./swatch-3.2.3.tar.gz
$ cd swatch-3.2.3
$ sudo cpan
OR
$ perl Makefile.PL
# Get CPAN prerequisites (not originally on my box)
$ sudo cpan Date::Calc Date::Format Date::Manip File::Tail
$ make && make test
$ sudo make install
$ make realclean
$ sudo mkdir /etc/swatch
$ sudo vi /etc/swatch/.swatchrc
Add these lines:
watchfor /Priority\: 1/i
mail addresses=USERNAME\@DOMAIN,subject=[SNORT] Priority 1 Alert
# Launch swatch as daemon. We will set up a StartupItem item to take care of this at launch
$ /opt/local/bin/swatch --daemon -c /etc/swatch/.swatchrc -t /var/log/snort/alert
$ ps -ef | grep swatch | grep -v grep
$ kill -9 <swatch pid>
# Caution against the use of a Swatch launchctl plist file: Swatch has been written so that the script completes and restarts.
# Any process that is started by launchd is apparently restarted after it's killed. This can lead quickly to a few thousand unwanted emails.
# Create StartupItem
$ sudo mkdir /opt/local/var/run/swatch [if you don't want to use /var/run]
$ sudo SystemStarter start Swatch
# Details: The only way I know how to do this is show an "ls -lR" of the directory structure.
# The permissions must be set up EXACTLY as they appear here or the StartupItem will fail.
$ ls -lR /Library/StartupItems/Swatch
total 16
drwxr-xr-x 3 root wheel 102 Mar 5 2010 Resources
-rw-r--r--@ 1 root wheel 553 Oct 9 21:40 StartupParameters.plist
-rwxr-xr-x 1 root wheel 722 Oct 11 10:31 Swatch
/Library/StartupItems/Swatch/Resources:
total 0
drwxr-xr-x 3 root wheel 102 Jul 22 2010 English.lproj
/Library/StartupItems/Swatch/Resources/English.lproj:
total 8
-rw-r--r-- 1 root wheel 286 Oct 9 21:44 Localizable.strings
# /Library/StartupItems/Swatch/Swatch
$ cat /Library/StartupItems/Swatch/Swatch
#!/bin/sh
# Swatch Boot Script
. /etc/rc.common
SWATCH_PIDFILE="/opt/local/var/run/swatch/swatch.pid"
StartService ()
{
ConsoleMessage "Starting Swatch log monitor"
/opt/local/bin/swatch --daemon --pid-file $SWATCH_PIDFILE -c /etc/swatch/.swatchrc -t /var/log/snort/alert
}
StopService ()
{
ConsoleMessage "Stopping Swatch log monitor"
if [ -f "$SWATCH_PIDFILE" ]
then
kill -9 `cat "$SWATCH_PIDFILE"` && rm "$SWATCH_PIDFILE"
fi
}
RestartService ()
{
ConsoleMessage "Restarting Swatch log monitor"
if [ -f "$SWATCH_PIDFILE" ]
then
kill -9 `cat "$SWATCH_PIDFILE"` && rm "$SWATCH_PIDFILE"
fi
/opt/local/bin/swatch --daemon --pid-file $SWATCH_PIDFILE -c /etc/swatch/.swatchrc -t /var/log/snort/alert
}
RunService "$1"
# StartupParameters.plist
$ cat /Library/StartupItems/Swatch/StartupParameters.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Description</key>
<string>Swatch (Simple Watchdog) Log Monitor</string>
<key>Messages</key>
<dict>
<key>start</key>
<string>Starting Swatch log monitor</string>
<key>stop</key>
<string>Stopping Swatch log monitor</string>
</dict>
<key>OrderPreference</key>
<string>Late</string>
<key>Provides</key>
<array>
<string>Swatch</string>
</array>
</dict>
</plist>
# Localizable.strings
$ cat /Library/StartupItems/Swatch/Resources/English.lproj/Localizable.strings
/* IMPORTANT !!! -- this string must be present and match the start message in StartupParameters.plist */
"Starting Swatch log monitor" = "Starting Swatch log monitor";
/* Also include stop message (not sure if used) */
"Stopping Swatch log monitor" = "Stopping Swatch log monitor";
$ sudo SystemStarter start Swatch
Webserver
# Apache web server for base: Create password with $ sudo htdigest /opt/local/share/base/.htdigest Snort Base
# Make sure that /etc/apache2/httpd.conf is set up to load this configuration file, which uses htdigest for access security
# snort-base.conf
$ cat /etc/apache2/extra/snort-base.conf
Alias /base /opt/local/share/base
<Directory "/opt/local/share/base">
# For RewriteRule issues, see https://discussions.apple.com/thread/1637654
Options Indexes MultiViews FollowSymLinks
AuthType Digest
AuthName "Base"
AuthUserFile /opt/local/share/base/.htdigest
AuthGroupFile /dev/null
Require user Snort
# RewriteEngine on
# RewriteLog /var/log/apache2/rewrite.log
# RewriteLogLevel 9
# RewriteRule ^(.*)base_qry_main.php $1foo
AllowOverride All
Order allow,deny
Allow from all
</Directory>
Alias /adodb /opt/local/share/adodb
<Directory "/opt/local/share/adodb">
AuthType Digest
AuthName "ADODB"
AuthUserFile /opt/local/share/base/.htdigest
AuthGroupFile /dev/null
Require user Snort
Options Indexes MultiViews
AllowOverride All
Order allow,deny
Allow from all
</Directory>
# Restart Apache. I'm still not sure which is necessary on Lion Server. One or both of these commands will work.
$ sudo /usr/sbin/apachectl restart
$ sudo serveradmin stop web && sudo serveradmin start web
# Browse to Base:
[Login with Snort/Password]
One final note: my Lion's web server returns a 400 Bad Request error for web pages that use a hex %23 (ascii #) in their urls, which affects some BASE queries. Any pointers to a fix to this problem would be greatly appeciated.
Mac mini, Mac OS X (10.7.1), 8 GB