Linux/snortのインストール

snortの導入(2017-08-13、更新:2019-10-12)


フリーのIDS(侵入検知システム)として名前が出てくるsnort*1ですが、
snort.org で manualの頭だけ読んだところ、つまりは tcpdump的なものなのかな
と思って、まずは軽い気持ちで入れてみることにしました。



snort のインストール

snort.org の導入事例通りにやりました、という内容のメモです。

前提として、
メールアドレスを snort.org へ登録することで
snapshot ルールファイルを貰えるようになります。
(無料で数日遅れ、有料で最新のルールファイルをダウンロードできるらしい)
たしかメールアドレスを登録しただけで、個人情報とかは要りませんでした。
試しに使ってみるだけ、あるいは監視ルールを自分で作る場合は登録は不要です。

では、インストールしていきます。
ソースコードを snort.orgの [Downloads] - [Sources] から
snort と daq の .tar.gz ファイルを落とします。
おなじページに MD5s というリンクもあるので、そちらで md5sumは参照。

# md5sum snort-2.9.9.0.tar.gz
# md5sum daq-2.0.6.tar.gz
(MD5s にある値と同じ結果になる事)
# tar zxvf snort-2.9.9.0.tar.gz

セットアップ方法は、同じく snort.org で [Documents] - [Snort Setup Guides] に
環境ごとのセットアップ例を提供してくれています。(英語)
ほぼ例通りで上手くいったので、以下たいしてメモを残していません。
今回はCentOS 7なので、Fedoraのファイル CentOS 7の手順がありました。。

まず依存するパッケージを入れます。
セットアップ例を見ると私の環境では
libdnet-devel、libpcap-devel の2つは入って無かったので、
(libpcapは入っているのですが、libpcap-develは無かったので)
先に 「yum install libdnet-devel libpcap-devel」しました。

(2019.10追記)
あと2.0.6の頃には無かったLuaJITを見なかったことにして突き進んだら
snort.2.9.15 のconfigure 時にエラーになりました。
CentOS7の手順書pdfファイルの通り、luajit.org から探してダウンロードしましょう。

それを踏まえて、セットアップ例のままにインストールしています。

# tar zxvf daq-2.0.6.tar.gz
# ./configure
# make
# make install
# cd ../snort-2.9.9.0/
# ./configure --enable-sourcefire
# make
# make install
# snort -V
  ,,_     -*> Snort! <*-
 o"  )~   Version 2.9.9.0 GRE (Build 56)
  ''''    By Martin Roesch & The Snort Team: http://www.snort.org/contact#team

かわいい豚?のAA(アスキーアート)も出たので、インストールできたようです。
その次は、Documentにそって メールアドレスとパスワードをSign Up しました。
これでRegistered されて、最新から一週遅れ?のルールがダウンロードできるようになります。
(あとで商用ユーザに登録して、有料で最新ルールをもらうこともできるらしい)

そのあと、Documentどおりに設定を進めます。
とはいえ、一応の読み替えは必要です。
ちゃんと設定する必要がある場合、2つ以上の手順書を読み比べたほうが良いかも知れません。
ディストリビューションが違えど同じ内容になりそうな箇所とか、
手順を読み替える/修正するところの手がかりになると思います。
以下、参考まで

  • 特にスクリプト例は、PDFファイルからコピペすると
    文字化けとか不要な改行とか入ってしまうので気を付けましょう。
  • useradd は自分の環境に合わせる、conf、log、rule の場所も。
  • INTERFACEなど、自分の環境で設定する
    セットアップ例は仮想OS環境で作ってるんでしょうね。
  • くれぐれも、そのまま鵜呑みにはしない事
    ファイルの誤記?抜け?snort以外のpermission変えそうになったり...気をつけましょう

あと、ほかには
「HOME_NET」は自分の環境に合わせます。EXTERNAL_NET も !$HOME_NET とか、よしなに。
「HTTP_PORTS」は、自分の環境に合わせて絞りました、ORACLEやSIPは現時点では不要なので。あとで直す予定です。

設定例のPDFファイルを辿るだけですが、結構時間かかってしまいました。
...それでも、読み替えが要るとはいえ、こういう設定の具体例(pdf手順書)があるのは
ゼロから作るよりは手がかりがある分、はるかに助かります。

動作&ログ確認は
実際にルールに書き加えてしまうのが一番手っ取り早い気がします。

# vi  rules/local.rules
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS 80 (msg:"HTTP/80 Test. Out-to-In."; sid:1000123; rev:1;)
(snort を再起動。起動完了後にweb アクセスさせる)
# tail /var/log/snort/alert

alert にログが表示されるのを確認しましょう。

なお、ルールには優先順位が有ります。(ソースファイルの doc/README.alert_order を参照)
まだこの辺の仕様がいまいち理解しきれていないのですが、
拒否するつもりが、他のルールで許可していましたとかは目も当てられないので気をつけましょう。

次は pulledpork を使って、最新のルールファイルを入手していきます。
もちろん pulledporkではなく手動で、snort.org からダウンロードしてきてもOKです。

pulledpork の導入

https://www.snort.org/oinkcodes に、
ルールファイルの入手には pulledpork が使えると説明があったので、
それを使ってみます。

perl のツール、みたいですね。

上記 URL から github へのリンクがあるのでそこから入手して適当な場所に展開。
etc/pulledpork.conf の内容を更新しましょう。
oinkcode は snort.org へ登録したメールアドレスでサインインすると確認できます。

※etc/pulledpork.conf を更新します
rule_url= の部分に自分のoinkcode を入れる。< > で囲む必要はありません。
rule_path= ほか、/etc/snort/rules 関連のPATHを自環境にあわせる
distro= の部分を自環境のOSディストリビューションにあわせる
sid_changelog= の部分も必要に応じて変更する
   ・・・追加書き込みだから、ログローテーションは自分でやらないとダメなのかな? snort本体のログも。

conf を更新したら、試しに実行

※実際は全部、フルPATHで書きます。
# pulledpork.pl -c pulledpork.conf -i disablesid.conf -T -H
Can't locate Crypt/SSLeay.pm in @INC (@INC contains:

エラーになりました。
(yum list | grep -i SSLeay とか、 yum info perl-Crypt-SSLeay とか見てみると)
たしかに、うちの環境には入ってなかったので追加しました。

# yum install  perl-Crypt-SSLeay

そして再実行で 501 エラー

Checking latest MD5 for snortrules-snapshot-2990.tar.gz....
       Error 501 when fetching https://www.snort.org/reg-rules/snortrules-snapshot-2990.tar.gz.md5 at /usr/local/pulledpork/pulledpork.pl line 534.

pulledpork に -vv を付けて実行すると、内容の詳細が出ます。

==> 501 Protocol scheme 'https' is not supported (LWP::Protocol::https not installed)

・・・はい、SSLeay と同様にこちらも確認、インストールします。

# yum install perl-LWP-Protocol-https

すると今度は、ここで止まります

** GET https://www.snort.org/reg-rules/snortrules-snapshot-2990.tar.gz.md5/自分のoinkcode ==>

これは gai.conf の更新 で解決しました・・・ が、後に gai.conf 無し接続できるようになったので
うちの環境依存の話題かもしれません。

tcpdump や wget で色々と確認してみたんですが、うちの環境だと
snort.org を名前解決すると IPv6 優先で帰ってきます。で
IPv6アドレスへhttps 接続しようとして固まる、ようです。
ためしに snort.org ではなく
IPv4アドレスを直打ちすると、とりあえず接続できたので、gai.conf で暫定対応しました。

なお、一度認証に失敗すると15分間は接続を受け付けなくなったので注意しましょう。

紆余曲折の後ようやく、実行できました。

# pulledpork.pl -c pulledpork.conf -i disablesid.conf -T -H
(中略。)
Done
Please review /var/log/snort/sid_changes.log for additional details
Fly Piggy Fly!

オプションの -H 指定によって、
pulledpork から SIGHUP を投げてsnort に設定を再読み込みさせるオプションが有るんですが、
そもそも、それに必要な pid ファイルを snort が作成しているかの確認は必要です。
(無い場合は、snort 起動時に --create-pidfile する等でファイル作成しましょう)
動作確認したら、snort のログ(デフォルトだとsyslog?)にも再起動の形跡があることを確認しましょう。
(syslogの例: snort: --== Reloading Snort ==--)

オプション -l で syslog に終了メッセージも出せるみたいです。
(syslogの例:pulledpork[xxxxx]: INFO: Finished Cleanly )
その他、pulledport.pl のオプションは README.txt に書いてあります。

あとは cron に仕込んで様子見です。
その記述例も https://www.snort.org/oinkcodes に書いてあります。
cron実行時の pulledpork 出力を消すなら実行コマンドの最後に「 >/dev/null 2>&1 」も追記しましょう。

後日談、気になるアクセスを止める例

動作確認用に作った「他のサーバへのhttpアクセス検知」の設定
「alert tcp $HOME_NET any -> $EXTERNAL_NET 80」が
alert.log に出ていたので肝が冷えました、サーバに侵入されたかと思って・・・

07/26-05:33:xx.xxxxxx  [**] [1:1000111:1] HTTP/80 Test. In-to-Out. [**] [Priority: 0] {TCP} うちのアドレス:80 -> 海外のアドレス:80

そしてログのディレクトリには

snort.log.1234567890

みたいなログが出力されて、 tcpdump -r とかで中身が見れます。

# tcpdump -r /var/log/snort/snort.log.1234567890  host xx.xx.xx.xx | head
(ログ内容は一部変えてます)
reading from file /var/log/snort/snort.log.1234567890, link-type EN10MB (Ethernet)
05:33:22.123456 IP null-i.net.http > xx.xx.xx.xx.http: Flags [.], ack 1234567890, win 29200, length 0
05:33:22.123456 IP null-i.net.http > xx.xx.xx.xx.http: Flags [.], ack 1234567890, win 29200, length 0
(以下、複数行にわたって同じ内容。)

内容について、ここからは推測ですが、
誰かが海外のWebサイト xx.xx.xx.xx へ嫌がらせしようとしているんでしょうね。
具体的には、送信元IPアドレスを xx.xx.xx.xx に詐称して、
うちの null-i.net や他所のWebサーバへ大量にアクセスして、
その応答(ack)を xx.xx.xx.xx へぶつける、とか。
IPスプーフィング のような、たぶん。

頻度は少ないですが、その後も発生しているので、止めることにしました。
ポート80,443(http, https)からのアクセスは無視しても良いでしょう。*2
向きに注意。送信「元」が80です。「先」ではないですよ。

# firewall-cmd --add-rich-rule 'rule family=ipv4 source-port port=80 protocol=tcp drop' --permanent
# firewall-cmd --add-rich-rule 'rule family=ipv4 source-port port=443 protocol=tcp drop' --permanent
(あるいは、 port=1-1023 のように範囲指定する)
# firewall-cmd --reload
(以下で確認。追加する前にも実行して差分を見ても良いかも)
# firewall-cmd --list-all
# iptables -nvL

もっとシンプルに指定のポートを、zone=drop を使って追加できるのかもしれませんが、
私の指定方法が間違っているのか、有効にならなかったので
(iptables -nvL に載っていないのと、後述の動作確認でdropできなかった)
今回は add-rich-rule で追加しました。まぁ、他のルールもあるので一カ所にまとまると良いですし。
ルールを消すときは、addを、remove-rich-ruleに変えて同じコマンドになります。

これの動作確認は、少し手間かもしれません。
まず実験するなら先に、80、443よりも簡単なポートをadd-rich-ruleでdrop検証した方が楽です*3
それから、localhostだとfirewallに引っかからないかもしれないので、外の接続環境からアクセスしてみましょう。
そして、送信元ポートをdrop対象にしないといけません。opensslだと bind IP:Port オプションでやれそうですね。

openssl s_client  -connect サーバ側ホスト:443   -debug  -bind クライアント側IP:ポート
(接続後はHTTPリクエストを自力で入力するか、"Q"リターンで切断。接続可否だけ分かれば良いので。)

受け側のWebサーバは、アクセスログで確認するか、tcpdumpで待っても良いでしょう。

tcpdump port 443
(root権限が必要かも。必要に応じて -i でインタフェースも指定)

これでクライアント側ポートを制限対象にした場合は接続できず、対象外は接続できることを確認しましょう。


それにしても、
他の不正アクセスもそうですが、Web公開すると常にこういう事故に巻き込まれますね。
たとえば他の(Webサーバとして使っていない)サーバの snort や ファイヤウォールのログなんて
ほんとうに静かなものです・・・

さておき、snort などのネットワーク監視ツールを使えば
(HTTPやSMTPより下の層の)TCP接続有無のようなログとして残り辛いものを見たい場合に便利そうです。
監視自体がサーバへの負荷がかからないか気になりましたが、
いまの所は特に気になりません。
なんだか色んなアクセスあるな~という形跡を見るだけでも、面白いですね。


*1 snort: (動物が)鼻を鳴らす、pulled pork:豚肉。どうやら豚がマスコット?らしい。検出するのがトリュフとかなら良いんですけどね。
*2 というよりも、1024以下のポートを送信「元」として使って来ることなんてありえ無い、はず。
*3 1023以下のポートは管理者権限しか bindできないのと、80は既に他のプロセス(=Webサーバ)が使用済みかもしれないので