2005年09月22日

Solaris10 に Snort 2.4.1 で PostgreSQL 連携なメモなのですよ。

PostgreSQL がインストールされていることが前提なのですよ。
良かったら先に オレオレ Solaris10 に PostgreSQL 8.0.3 をインストールするメモ を読んであげてください、なのですよ。

snort ご本家 からソースアーカイブを持ってくるですよ。

> wget http://www.snort.org/dl/current/snort-2.4.1.tar.gz
> gzcat snort-2.4.1.tar.gz | tar xf -
> cd snort-2.4.1/
> pwd
/export/home/mass/src/snort-2.4.1

以下の環境変数を設定しておくのですよ。
setenv  LD_LIBRARY_PATH "/usr/local/lib:/usr/local/pgsql/lib:/opt/sfw/lib:/usr/sfw/lib:/usr/lib:/lib"
setenv  LDFLAGS         "-L/usr/local/lib:-L/usr/local/pgsql/lib:-L/opt/sfw/lib:-L/usr/sfw/lib:-L/usr/lib:-L/lib"

てけとーに build して install するですよ。
prefix は /usr/local/snort としてみたのですよ。
> ./configure --prefix=/usr/local/snort --with-snmp \
--with-postgresql=/usr/local/pgsql --with-libpq-includes=/usr/local/pgsql/include \
--with-libpq-libraries=/usr/local/pgsql/lib CFLAGS='-O3 -pipe -mcpu=v9'
> make
> make check
> su
Password:
# make install

さっそく packet dump mode で動かしてみるのですよ。
Solaris10 の Companion CD とかからフルインストールしてると Ver. 2.0.0 の snort とかが /opt/sfw/bin に入っているのでちぅいなのですよ。
初回に snort -V は必須なのですよ。
# rehash
# snort -V
# snort -dev -i hme0
てきとーに ping とかしてみてキャプチャできてれば OK ! ですよ。

snort 用のデータベースを作るのですよ。
snort のソースアーカイブに各 RDBMS 用の SQL スクリプトが同梱されているので、それを流し込めばいいのですよ。
# pwd
/export/home/mass/src/snort-2.4.1
# cp schemas/create_postgresql ~postgres/
# su - portgres
> createdb snort
> psql snort < create_postgresql
> psql snort
  ...messages...
snort=# \d
                         List of relations
 Schema |                Name                |   Type   |  Owner
--------+------------------------------------+----------+----------
 public | data                               | table    | postgres
 public | detail                             | table    | postgres
 public | encoding                           | table    | postgres
 public | event                              | table    | postgres
 public | icmphdr                            | table    | postgres
 public | iphdr                              | table    | postgres
 public | opt                                | table    | postgres
 public | reference                          | table    | postgres
 public | reference_ref_id_seq               | sequence | postgres
 public | reference_system                   | table    | postgres
 public | reference_system_ref_system_id_seq | sequence | postgres
 public | schema                             | table    | postgres
 public | sensor                             | table    | postgres
 public | sensor_sid_seq                     | sequence | postgres
 public | sig_class                          | table    | postgres
 public | sig_class_sig_class_id_seq         | sequence | postgres
 public | sig_reference                      | table    | postgres
 public | signature                          | table    | postgres
 public | signature_sig_id_seq               | sequence | postgres
 public | tcphdr                             | table    | postgres
 public | udphdr                             | table    | postgres
(21 rows)

snort=#
table などもろもろが登録されていることをしっかとその目で確認するのですよ。

snort データベース専用のユーザー snortusr を登録するのですよ。
ユーザー名はもうドキュメントそのままに。
snort=# CREATE USER snortusr WITH PASSWORD 'hogehoge';
CREATE USER
このままでは snortusr から snort データベースに対して一切権限がなく、 SELECT す らもできない状態なので、 snort データベースの各 table / sequence に対して必要な 権限を設定してゆくのですよ。
ここで同梱のドキュメント(doc/README.database)通りにやってみると、
snort=# grant INSERT,SELECT on snort.* to snortusr@localhost;
ERROR:  syntax error at or near "to" at character 32
LINE 1: grant INSERT,SELECT on snort.* to snortusr@localhost;
                                       ^
と syntax error になるのですよ。ふざけるなですよ。
ここは
snort=# \q
\q でおとなしく引き下がるのですよ。

ここで力業スクリプトの登場ですよ。
#!/bin/sh

for i in `psql -c "\d" snort | grep "^ public" | awk '{ print $3 }'`; do
  psql -c "GRANT INSERT, SELECT ON $i TO snortusr;" snort > /dev/null
  if [ -n "`echo $i | egrep '^sensor$|_seq$'`" ]; then
    psql -c "GRANT UPDATE ON $i TO snortusr;" snort > /dev/null
  fi
done
psql で table などを一覧して、さらに psql で GRANT を一回一回実行ですよ。しゅごい効率悪しゅぎ、ですよ。
やってることがわかっていただければそれでいいのですよ。
上記スクリプトを grant_snortdb.sh とか適当に保存して、
> sh grant_snortdb.sh
ちょっとだけ時間がかかりますが、プロンプトが帰ってくるのですよ。
権限が正しく設定されたか psql 上から確認するのですよ。
> psql snort
  ...messages...
snort=# \z
                                   Access privileges for database "snort"
 Schema |                Name                |   Type   |                 Access privileges
--------+------------------------------------+----------+---------------------------------------------------
 public | data                               | table    | {postgres=arwdRxt/postgres,snortusr=ar/postgres}
 public | detail                             | table    | {postgres=arwdRxt/postgres,snortusr=ar/postgres}
 public | encoding                           | table    | {postgres=arwdRxt/postgres,snortusr=ar/postgres}
 public | event                              | table    | {postgres=arwdRxt/postgres,snortusr=ar/postgres}
 public | icmphdr                            | table    | {postgres=arwdRxt/postgres,snortusr=ar/postgres}
 public | iphdr                              | table    | {postgres=arwdRxt/postgres,snortusr=ar/postgres}
 public | opt                                | table    | {postgres=arwdRxt/postgres,snortusr=ar/postgres}
 public | reference                          | table    | {postgres=arwdRxt/postgres,snortusr=ar/postgres}
 public | reference_ref_id_seq               | sequence | {postgres=arwdRxt/postgres,snortusr=arw/postgres}
 public | reference_system                   | table    | {postgres=arwdRxt/postgres,snortusr=ar/postgres}
 public | reference_system_ref_system_id_seq | sequence | {postgres=arwdRxt/postgres,snortusr=arw/postgres}
 public | schema                             | table    | {postgres=arwdRxt/postgres,snortusr=ar/postgres}
 public | sensor                             | table    | {postgres=arwdRxt/postgres,snortusr=arw/postgres}
 public | sensor_sid_seq                     | sequence | {postgres=arwdRxt/postgres,snortusr=arw/postgres}
 public | sig_class                          | table    | {postgres=arwdRxt/postgres,snortusr=ar/postgres}
 public | sig_class_sig_class_id_seq         | sequence | {postgres=arwdRxt/postgres,snortusr=arw/postgres}
 public | sig_reference                      | table    | {postgres=arwdRxt/postgres,snortusr=ar/postgres}
 public | signature                          | table    | {postgres=arwdRxt/postgres,snortusr=ar/postgres}
 public | signature_sig_id_seq               | sequence | {postgres=arwdRxt/postgres,snortusr=arw/postgres}
 public | tcphdr                             | table    | {postgres=arwdRxt/postgres,snortusr=ar/postgres}
 public | udphdr                             | table    | {postgres=arwdRxt/postgres,snortusr=ar/postgres}
(21 rows)

snort=#
Access privileges フィールドの snortusr を確認するのですよ。
ほとんどの table が以下のようになってるはずですよ。
snortusr=ar/postgres
snortusr に対して、「a : INSERT(append)」「r : SELECT(read)」の権限を postgres ユーザーが設定したよ、という意味ですよ。
あと、 sensor table と全ての sequence が以下のようになってるはずですよ。
snortusr=arw/postgres
これは a, r に加えて、「w : UPDATE(write)」の権限も設定されているのですよ。
名前の末尾に _seq と付くもの(sequence)は UPDATE 権限が必要なようですよ。動作確認したときに sequence に a, r しか設定していなくて snort がエラー吐きまくってし ばらく苦労したのは秘密ですよ。

権限については PostgreSQL 8.0.3 文書 - GRANT ( 日本 PostgreSQL ユーザ会) に詳しく記載されているのですよ。

さて、データベースの設定も済んだので snort の設定に戻るのですよ。
snort=# \q
> exit
psql を \q で終了し、 postgres ユーザーも終了ですよ。

ソースアーカイブ同梱の etc 以下の設定ファイル群をコピーですよ。
# pwd
/export/home/mass/src/snort-2.4.1
# cd etc
# ls | grep -v Makefile | xargs -n 1 -I {} cp {} /usr/local/snort/etc/

snort 公式のルールセットを取得して展開するですよ。 VRT ライセンスだかなんだかややこしいことになってるので、無難な unregistered user release を使うことになるのですよ。
/usr/local/snort/rules 以下に展開ですよ。
# cd /usr/local/snort
# wget http://www.snort.org/pub-bin/downloads.cgi/Download/vrt_pr/snortrules-pr-2.4.tar.gz
# gzcat snortrules-pr-2.4.tar.gz | tar xf -
今度は the Bleeding Edge of Snort のルールセットをゲッツするですよ。
同じく /usr/local/snort/rules 以下に展開するのですよ。
# pwd
/usr/local/snort
# wget http://www.bleedingsnort.com/bleeding.rules.tar.gz
# gzcat bleeding.rules.tar.gz | tar xf -
展開したら公式ルールと Bleeding Snort の sid-msg.map を結合するのですよ。
# cd /usr/local/snort/rules/
# cp sid-msg.map sid-msg.map.orig
# cat bleeding-sid-msg.map sid-msg.map.orig | sort -n > sid-msg.map

ようやく snort.conf をいぢるのですよ。
はぢめての snort なのでとにかく初期設定のまま、 Bleeding Snort のルールを有効にしつつ PostgreSQL へログを吐き出しちゃったりする設定なんかを書いちゃったりなんかするのですよ。
# cd /usr/local/snort/etc/
# vim snort.conf
# ---- conf ファイル内のコメントを適当に読みつつ以下を追加ですよ。
# Bleeding Snort variables
var SSH_PORTS 22
var SSH_CLIENT_HOSTS any
var SSH_SERVER_HOSTS any

# Bleeding Snort rules
include $RULE_PATH/bleeding-attack_response.rules
include $RULE_PATH/bleeding-custom.rules
include $RULE_PATH/bleeding-dos.rules
include $RULE_PATH/bleeding-exploit.rules
include $RULE_PATH/bleeding-inappropriate.rules
include $RULE_PATH/bleeding-malware.rules
include $RULE_PATH/bleeding-p2p.rules
include $RULE_PATH/bleeding-policy.rules
include $RULE_PATH/bleeding-scan.rules
include $RULE_PATH/bleeding-virus.rules
inclode $RULE_PATH/bleeding-web.rules

output database: log, postgresql, user=snortusr dbname=snort password=hogehoge
snort.conf 自体は上記の通り DB パスワードも記述されているので、一般ユーザーに閲覧できないよう read 権限を絞っちゃうのですよ。ギュッとねっ!
# chmod go-r snort.conf
# env LANG=C ls -l snort.conf
-rw-------   1 root     root       30203 Sep 20 00:40 snort.conf

snort プロセス用のユーザー & グループを作るのですよ。
危険なネットワーク域を扱うプロセスは専用ユーザーで動かすのが安全なのですよ。
# groupadd -g 48 snort
# useradd -d /usr/local/snort -g snort -u 48 snort
# vipw
snort:x:48:48::/usr/local/snort:
  ↑ snort ユーザーのシェルを消去。 Solaris の流儀?

snort 用のログディレクトリを作るのですよ。
作らないとぶーたれるはず。
# mkdir /var/log/snort
# chown snort:snort /var/log/snort

ひととおり設定はできたのですよ。いざ NIDS モードで起動するのですよ。
# snort -u snort -g snort -deD -k none -i hme0 -c /usr/local/snort/etc/snort.conf
"-i hme0" の hme0 は適宜自分が観測したいインターフェイス名で置き換えるのですよ。
snort.conf で "output database: log, ..." な設定をしていると、 /var/log/snort/ 以下に alert ファイルが作成され、検知したアラートがテキスト化されて追記されてゆくのですよ。 PostgreSQL の snort データベースにも記録されているのですが、まずはこのファイルで検知されているか確認するのですよ。
snort データベースへの記録状況は "psql snort" して適当に "SELECT * FROM event;" とかやってみて確認するのですよ。
ちなみに snort.conf のパーミッションを root:root の 600 にしてるのですが、 snort プロセス起動時は root 権限で起動して snort.conf を読み込んだ後、ほどなくして snort ユーザー権限に移行するようなので、 Permission denied で落ちる心配はないようなのですよ。

もしここまで来て snort がまともに動かないなどといった場合は適当になんとかするのですよ。ちなみに Version 2.4.0 はそこそこ signal 11 とかでこけてた気がするのですよ。

さて、ですよ。
なんとなくまともに動いているような雰囲気を醸し出すようになったら、 rc スクリプトを登録するのですよ。
うちは Quad Fast Ethernet NIC自作 Ether TAP をかまして、
2005092201.png
のような構成にしているため、 snort の監視対象インターフェイスが 4つになるのです よ。でも Solaris 上では "-i any" のような指定は却下(Linux だと OK?)のため、デ ーモンモードの snort を 4つ動かすことになるのですよ。
rc スクリプトは以下のようになるのですよ。
#!/bin/sh

NAME="snort"
CONF_FILE=/usr/local/snort/etc/snort.conf

BIN="snort"
PROG="/usr/local/snort/bin/${BIN}"
FLAG="-u snort -g snort -deD -k none -c ${CONF_FILE}"

#
# if changes this variable, change "net_detect()" function
# and "MAIN SWITCH".
IF_EXT="ife0 ife1"
IF_DMZ="ife2 ife3"
IF_ALL="$IF_EXT $IF_DMZ"

LD_LIBRARY_PATH=/usr/local/lib:/usr/local/pgsql/lib:/opt/sfw/lib:/usr/sfw/lib:/u
sr/lib:/lib
export LD_LIBRARY_PATH

#
# Start snort
start() {
    for IF in `eval echo \\$IF_${ARGS}`; do
        proc_detect
        if [ -n "$PID" ]; then
            echo "$NAME on $IF[$NET] still running. PIDs: $PID"
        elif [ -f $CONF_FILE -a -x $PROG ]; then
            $PROG -i $IF $FLAG > /dev/null 2>&1
            proc_detect
            echo "$NAME on $IF[$NET] starting. PIDs: $PID"
        fi
    done
}

#
# Stop snort
stop() {
    for IF in `eval echo \\$IF_${ARGS}`; do
        proc_detect
        if [ -z "$PID" ]; then
            echo "$NAME on $IF[$NET] not running."
        else
            kill -TERM ${PID}
            echo "$NAME on $IF[$NET] terminated. PIDs: $PID"
        fi
    done
}

#
# Show PID
status() {
    echo ""
    echo "$NAME running under PIDs [$ARGS]:"
    for IF in `eval echo \\$IF_${ARGS}`; do
        proc_detect
        test -z "$PID" && PID="Not running"
        echo "  $IF[$NET] : $PID"
    done
    echo ""
}

#
# Detect PID and the network where interface belongs to.
proc_detect() {
    PID=`ps -eo pid,args | \
        awk "\\$2 ~ /\\/${BIN}\\$/ && \\$4 ~ /^${IF}\\$/ \
        { print \\$1 }"`
    NET=`echo $IF_EXT | awk "\\$0 ~ /$IF/ { print \\"EXT\\" }"`
    test -z "$NET" && NET=`echo $IF_DMZ | \
        awk "\\$0 ~ /$IF/ { print \\"DMZ\\" }"`
}

#
# Show usage
usage() {
    echo ""
    echo "Usage:"
    echo "  `basename $0` { start | stop | restart | status } [ext|dmz]"
    echo ""
}

#
# MAIN SWITCH
case "$2" in
  ext)  ARGS="EXT";;
  dmz)  ARGS="DMZ";;
  *)    ARGS="ALL";;
esac

case "$1" in
  start)
        start $ARGS
        ;;
  stop)
        stop $ARGS
        ;;
  status)
        status $ARGS
        ;;
  restart)
        stop $ARGS
        sleep 5
        start $ARGS
        ;;
  *)
        usage
        exit 1
esac

exit 0
最近 sh スクリプトすきすきーなのですよ。
上記スクリプトを一通り動作確認した上で、 /etc/init.d/snort として配置するのですよ。
# cp <hogehoge> /etc/init.d/snort
# chmod +x /etc/init.d/snort
# ln -s /etc/init.d/snort /etc/rcS.d/K01snort
# ln -s /etc/init.d/snort /etc/rc0.d/K01snort
# ln -s /etc/init.d/snort /etc/rc1.d/K01snort
# ln -s /etc/init.d/snort /etc/rc2.d/S99snort

ふはー。ようやくまともに動いたのですよ。
さぁ次は解析ツール入れたりルールの自動更新させたりルールのチューニングしたり、やるべきこと/やりたいことがてんこ盛りなのですよ。
でも次の更新はいつになることやら... なのですよ。


参考リンク:
HRK's OpenBSD Memo - Snort をインストールする
にわか鯖管のメモ - Snortインストール手順
snort ご本家
the Bleeding Edge of Snort


---- 10/9 更新
/etc/init.d/snort スクリプト中にミスがあったので修正なのですよ。
1. LD_LIBRARY_PATH を追加したのですよ。実は OS 起動時に実行されていなかったのですよ。
2. ps で表示させるフィールドを -o オプションで限定したのですよ。
  ps -ef での STIME フィールドって起動してから一日以上経ったプロセスに対して書式が変わるってことを失念していたのですよ。

Posted by mass at 2005年09月22日 00:21 [UNIX] | TrackBack
Comments
Post a comment









Remember personal info?