LoginSignup
4
3

More than 3 years have passed since last update.

blacklistd 始めました

Last updated at Posted at 2020-12-26

はじめに

FreeBSDで blacklistd が導入されて早3年1。全く新しく環境構築を行う機会を得たので、この際だから乗り換えてみようと検証してみた。
結論から言うと微妙かな。半日検証してみての結論なので判断が早すぎかも知れないけど。とは言え定石的なものは見えたのでメモがてら残しておく。とりあえず長期的に運用してみて判断かな。

検証環境

  • OS: FreeBSD(12.2-R
  • ファイアウォール: IPFW2バックエンド
  • サーバーソフトウェア: SSHd(OpenSSH_7.9p1, OpenSSL 1.1.1h-freebsd 22 Sep 20203

設定項目

  1. IPFWの設定
  2. blacklistd の設定
  3. SSHdの設定

IPFWの設定

取り急ぎIPFWを使用「していない」ものとして、ゼロからセットアップする。既にIPFWを運用中で、そのルールの中に入れたい場合は、本説明を参考に組み込んで欲しい。

/etc/rc.conf

/etc/rc.conf に下記の設定を追加する。

firewall_enable="YES"
firewall_type="/etc/ipfw.conf"

あとはお好みで firewall_quiet="YES" を加えてもいい。
また色々と解説しているサイトを見てると firewall_type="OPEN" を指定してる例もあるが、それでも十分ではある。今回はそれらの半歩先ゆく設定ということで。

/boot/loader.conf

/boot/loader.conf に下記の設定を追加する。

net.inet.ip.fw.default_to_accept="1"

本設定後再起動するまでは、下記コマンドを実行しておくこと。

kenv net.inet.ip.fw.default_to_accept="1"

この設定はファイアウォールのデフォルトルール(ルール番号65535)を「全てのアクセスを許可する」というものである。本設定はIPFW有効後には変更できないので注意。
一応IPFWが有効になった直後にアクセスできなくなることを防ぐための設定だが、ポリシー上分かって設定してるなら無視してもよい。

以後の説明ではこの設定があることを前提に話を進める4

/etc/ipfw.conf

add    1 check-state :default
add 3000 allow tcp from any to any 22 in via インターフェース名 setup keep-state :default

ラベル(:default)はサービス毎に定義してもいいかもしれないけど、そこまでのファインチューニングは不要でしょう。

このファイルの中身を空っぽにすれば firewall_type="OPEN" と同等になる4

  • ルール番号1: 後に指定する keep-state のルールで許可した通信を【最速】処理する(以後のルールの解釈をさせない)。
  • ルール番号3000: 指定された「インターフェース名」に「in」してくる、SSH(ポート22)にセットアップパケット(TCP SYN)をステートを維持してアクセスを許可する5

ルール番号1はともかく、ルール番号3000なのは後に説明する。また、blacklistd が要求するIPFWのルールについても、この時点では取り上げない。

blacklistd の設定

/etc/rc.conf

/etc/rc.conf に下記の設定を追加する。

blacklistd_enable="YES"

/etc/ipfw-blacklist.rc

/etc/ipfw-blacklist.rc の中身はとりあえず空でもいいので、ファイルを作成する6

touch /etc/ipfw-blacklist.rc

この設定ファイルは /usr/libexec/blacklistd-helper というシェルスクリプトより参照され、ipfw_offset という設定が行える。この設定はデフォルトで 2000 と定義されている。

blacklistd ではIPFWルール番号「2000+ポート番号」にアクセス不許可(パケットをドロップさせる)のルールを追加する7。よってSSHd(ポート22)の場合、ルール番号は2022となる。

また拒否するIPアドレステーブルとして portポート番号 という名前のテーブルが使用される。SSHd(ポート22)の場合、テーブル port22 という名前になる7

# ipfw show
  :
02022     0        0 deny tcp from table(port22) to any 22
  :
# ipfw table port22 list

/etc/blacklistd.conf

いよいよ本機能が期待されるアタック避けの設定である。どのようにチューニングするかが腕の見せ所。
取り急ぎデフォルト設定をベースに解説する。問題を限定するために、SSHdに限定する。

# $FreeBSD: releng/12.2/usr.sbin/blacklistd/blacklistd.conf 336977 2018-07-31 16:39:38Z brd $
#
# Blacklist rule
# adr/mask:port type    proto   owner           name    nfail   disable
[local]
ssh             stream  *       *               *       3       24h
ftp             stream  *       *               *       3       24h
smtp            stream  *       *               *       3       24h
submission      stream  *       *               *       3       24h
#6161           stream  tcp6    christos        *       2       10m
*               *       *       *               *       3       60

# adr/mask:port type    proto   owner           name    nfail   disable
[remote]
#129.168.0.0/16 *       *       *               =       *       *
#6161           =       =       =               =/24    =       =
#*              stream  tcp     *               =       =       =

[local][remote]

本設定ファイルは [local][remote] のスタンザ(節)に分かれる。マニュアルによればそれぞれ以下の役割となっている。

  • [local] スタンザ(節)はデフォルト設定を記述する。
  • [remote] スタンザ(節)はカスタム(例外)設定を記述する。

そこで [local] スタンザ(節)の ssh stream * * * 3 24h に注目する。

ssh stream * * * 3 24h という設定

ロケーション ソケット型 プロトコル オーナー 名前 失敗回数 無効期間
ssh stream * * * 3 24h
  • *: デフォルトまたはワイルドカード一致を意味する。
  • =[local] の設定を踏襲する。
  • ロケーションは [<アドレス>|<インターフェース>][/<マスク値>][:<ポート>] という書式89で記述する。
    • 「アドレス」はIPv4の場合は数字表記(XXX.XXX.XXX.XXX)で、IPv6の場合は [] にくくられた数字表記([XXXX:XXXX::XXXX])である。
    • 「インターフェース」はインターフェース名(re0vmx0 等)。
    • 「マスク値」は数字表現(0~32または0~128)。
    • 「ポート」はポート番号ないしはポート名。ポート名は /etc/services をもってポート番号を解釈する。
  • ソケット型は「stream」、「dgram」が指定可能である。
  • プロトコルは「tcp」、「udp」、「tcp6」、「udp6」が指定可能である。
  • ソケットストリーム型とプロトコルは基本的10に「stream *」と指定するのが無難かな。
  • オーナーはイベントを報告してくるデーモン(ここではSSHd)の実行ユーザー名(またはユーザーID)である。
  • 名前はパケットフィルター規則の名前ですが、IPFWでは使用してない(NPFとPFだけ)ので無視でいいです。
  • 失敗回数はアクセスがブロックされる前に試行した失敗した回数である。* の場合無限回許される。
  • 無効期間は * (永遠)または時間(単位が無い場合は秒数)で、単位としては「s」(秒)、「m」(分)、「h」(時)、「d」(日)が指定できる。

アロー(許可)リストの作成

[remote] スタンザ(節)に #129.168.0.0/16 * * * = * * という例があるが、こういう形(もちろんコメントインで)でトラステッドネットワークからのアクセスに対し、blacklistd がアクセス拒否しないように設定する。
特にコンソールにアクセスできないような環境の場合、間違ってフィルター登録され、24時間もアクセスできないとなると被害が大きいこともあり、注意深く設定することが要求される。

SSHdの設定

カジュアルに設定するなら /etc/rc.conf に下記の設定をする。

sshd_flags="-o UseBlackList=yes"

運用に問題無いようであれば、/etc/ssh/sshd_config に反映する。

--- /etc/sshd_config.orig       2020-12-17 08:21:52.421625000 +0900
+++ /etc/sshd_config    2020-12-26 16:40:21.836724000 +0900
@@ -104,7 +104,7 @@
 #MaxStartups 10:30:100
 #PermitTunnel no
 #ChrootDirectory none
-#UseBlacklist no
+UseBlacklist yes
 #VersionAddendum FreeBSD-20200214

 # no default banner path

運用開始

再起動すれば全て立ち上がるといえば立ち上がるのだけど、設定ミスがあったりすると目も当てられないこともあり、手動で立ち上げる手順を示す。

IPFWの起動

service ipfw start

起動直後は ipfw show で設定確認すればOK。

# ipfw show
00001      0        0 check-state :default
00100      0        0 allow ip from any to any via lo0
00200      0        0 deny ip from any to 127.0.0.0/8
00300      0        0 deny ip from 127.0.0.0/8 to any
00400      0        0 deny ip from any to ::1
00500      0        0 deny ip from ::1 to any
00600      0        0 allow ipv6-icmp from :: to ff02::/16
00700      0        0 allow ipv6-icmp from fe80::/10 to fe80::/10
00800      0        0 allow ipv6-icmp from fe80::/10 to ff02::/16
00900      0        0 allow ipv6-icmp from any to any icmp6types 1
01000      0        0 allow ipv6-icmp from any to any icmp6types 2,135,136
03000      0        0 allow tcp from any to any 22 in via インターフェース setup keep-state :default
65535      0        0 allow ip from any to any

なおルール番号100から1000までは自動挿入である1112

blacklistd の起動

service blacklistd start

SSHdの再起動

service sshd restart

モニタリング

稼動状態をモニタリングするのであれば ipfw showipfw table port22 list を実行することで確認できる。
IPFWの場合「ルール番号」「パケット数」「バイト数」「ルール」という並びになるので、SSH接続があればルール番号3000のパケット数(例では578)を数えればよい。実際にアクセス拒否した回数はルール番号2022となる(例では216)。

# ipfw show
  :
02022    216    12960 deny tcp from table(port22) to any 22
03000    578    99786 allow tcp from any to any 22 in via インターフェース setup keep-state :default
65535 125299 44785979 allow ip from any to any

実際にアクセス拒絶となったIPアドレスは下記の通り確認できる。

# ipfw table port22 list
XXX.XXX.XXX.XXX/32 0
XXX.XXX.XXX.XXX/32 0

blacklistd が認識している状態(ブロック状態についても含む)は blacklistctl コマンドを使用して確認する。

# blacklistctl dump -a
        address/ma:port id      nfail   last access
XXX.XXX.XXX.XXX/32:22   OK      2/2     YYYY/mm/Dd HH:MM:SS
XXX.XXX.XXX.XXX/32:22   OK      2/2     YYYY/mm/dd HH:MM:SS

マニュアルにはヘッダーの意味が書いてないため調べたところ、id は無視していいです(NPFのみ使用)。今のところ「OK」と「」(ヌル)しか見てません。

チューニングポイント

サンプルでは3回間違えると24時間アクセスを拒否する設定になっているが、これを2回にして1分程度で解除するのも面白い。

# Blacklist rule
# adr/mask:port type    proto   owner           name    nfail   disable
[local]
ssh             stream  *       *               *       2       60s

一つには本当に間違ってアクセスしてしまった時のリカバリが1分で済む点と、アタックはそう長時間に渡って行われないためである。
実際に試してみるとフィルタリング能力としては、半日様子見て高々0.5%未満くらいである。なお24時間設定にして、2時間程度様子を見た場合は高々16%未満なので、短期間にアクセスして、またしばらくしてアクセスするといったパターンなのが分かる。
正直短期間のペナルティと長期間のペナルティを分けて設定できるようにして欲しいところ。 orz

また他のツールと違い、ポートスキャンレベルでは失敗にアタックと解釈されないため、鍵認証を必須にしているような環境では、ある程度回数を絞り込める余地はある。それでも流石に1回までしか許さないのはキツイと思うけど。

また拒否時間も24時間は長すぎる。確実に解除問い合せが来るので、長くても3分程度に抑えるべきであると考える。

よくある質問とその答え

Q.半歩先行く設定って?他の説明と何が違うの?

A.ステートフルインスペクション機能により、SSHのTCPセッションが生きてる間は、blacklistd の登録の影響を受けない点が違います。
実験中に誤って自分が接続しているIPがブロックされても、今生きてるSSHのセッションが生きてる間はリカバリできる余地があります。
また通信を遮断するにしても、TCP RSTパケットを送信しきれることから、TCPセッションタイムアウトを待たなくていいメリットがあります。
これは逆に、攻撃者側にとってもメリットを有することでもあるのですが、そもそも認証に失敗すればTCPセッションが切れることから、言うほどのメリットは無いです。むしろTCPセッションが確実に切れるメリット(リソース的に)の方が高いです。

Q.「微妙」という評価はなんで? blacklistd はよろしくない?

A.この手のツール13としては悪くないと思います。むしろ良い。
まず何よりも、従来のツールが各種ログを拾いながら、ブロックリストを生成するのと違い、各種サーバーソフトウェアが blacklistd に即座に通知する仕組みであるため、極めて迅速14にブロックリストが作られます。この点が他のツールとは大いに違うところになります。

それ故に期待値が上がってしまっているのですが、いわゆるログインエラーの類いについては上手く機能しています。ポートスキャンレベルの攻撃?は上手く拾えていません。もちろん拾えてない原因はSSHd側にあるのですが、この結果、あまりブロックしてる感じはしません。
またSSHdが全面的に悪いか、というとそうでも無く、マニュアルによれば、認証結果(成功・失敗)しか拾わないようです。
まあポートスキャンレベルで…という話はあるのでしょう。実際、ssh-keyscan や各種監視ツールではポートスキャンレベルといえばそうではありますが。

もう一つ期待外れな点としては、認証成功の記録を活用していない点です。認証成功をもってペナルティに対するガードとして機能してくれれば、アローリストの作成的にも嬉しいのですが。

Q.ブラックリスト…ホワイトリスト…

A.君のような勘の良いry。この変更は極めて影響が大きいので、メジャーバージョンアップ時(13-R)に変わるのではないかな、とみてます。

Q.ファイアウォールは必要ですか?

A.blacklistd そのものはフィルタリング処理はしないです。その手の処理はファイアウォールにアウトソースする仕組みになっています。
また対応しているファイアウォールも、IPFW、NPF、PF、IPFに限られています。優先順位も下記の通りとなります。

  1. /etc/ipfw-blacklist.rc というファイルがある場合、IPFWをバックエンドに使う。
  2. /etc/npf.conf というファイルがある場合、NPFをバックエンドに使う。
  3. /etc/pf.conf というファイルがある場合、PFをバックエンドに使う。
  4. /etc/ipf.conf というファイルがある場合、IPFをバックエンドに使う。

この辺りは /usr/libexec/blacklistd-helperマニュアル-C オプションの記述を参考に、ガチカスタマイズすることは可能です15

繰り返しますが、IPFW、NPF、PF、IPFしか対応してないのはベースシステムの制限であって、他のファイアウォールの選択を拒絶するものではありません。それ以外のファイアウォール(外部を含む)を使用したい場合は、上手く作り込んでください。

Q.ipfw_offset とか 2000 とか 3000 ってなんなんだよ。

A.IPFWのルール番号の指定です。blacklistd に対応を謳ってるサーバーが対象とするプロトコルはおおよそ3桁ポート番号なので、ipfw_offset に対して+1000した値で許可設定を入れてみました。ある意味ルール番号2999というのもありですが。
blacklistd がルールを挿入する位置とバランスを取ってルール番号を決めてください。

逆にガッチガチに制御したい向けは、blacklistd-C オプションを指定して、完全に自前で運用するしか無いです。

Q.やっべ、自分の接続元IPアドレスがブロックリストに登録されてしまった!

A.大丈夫だ。問題無い。現在 blocklistctl に解除する機能が無いので ipfw table port22 delete XXX.XXX.XXX.XXX/32 とコマンドを打って消そう!
なお拒否期限が残ってる間は blacklistd を再起動する度に登録されるのでよろしく!16

Q.何か改善点ありますか?

色々課題(blacklistctl の充実など)はあると思いますが、最低でもベイジアンフィルター、ナウでヤングには機械学習の実装が期待されるかと。
とりあえず仕組みは簡単なので、LL言語でプロトタイピングするのが吉かな。

参考文献


  1. 2020年末現在。2017年07月26日リリースの11.1-Rが初出。 

  2. 実際のフィルタリングにはIPFW、NPF、PF、IPFのどれかをバックエンドで指定する。 

  3. 取り急ぎSSHdのみで。他にも blacklistd 対応謳ってるサーバーソフトウェアあるけど、今回は詳細追わず。 

  4. 「全てのアクセスを許可」する前提で /etc/ipfw.conf の説明を行うので…。 

  5. 日本語でOK。 

  6. 設定の意味とファイアウォールバックエンドの選択については後述する。 

  7. そういうルール(命名規則?)なので細かく制御できない。 

  8. 指定不可能な組み合わせ(re0/24 など)があるみたいだけど未調査。 

  9. ssh がポート名というのは書式に合わない気がす。: はどうした。: は。微妙にマニュアルの表現が甘い気が。 

  10. 原則とは言わない。blacklistd に対応したサーバーソフトウェアとプロトコル考えると、大抵はTCP/IPだとは思うので。 

  11. /etc/rc.firewall 由来。setup_loopbacksetup_ipv6_mandatory による。 

  12. 強制的に入るので順番を変えたい等、何かしら調整したいなら /etc/ipfw.conf の最初に -f flush 入れるしかない。 

  13. 自分が他に試したのは SSHGuard くらいですが、他にも Fail2ban など。 

  14. 拒絶要件に達した直後、次の接続ではフィルタリングされているくらい早い。 

  15. 具体的なカスタマイズ例(外部ファイアウォールへのアウトソース)を考えてみたのだけど、意外と大変そうなのでアイデアのみで。 

  16. ハンドブックに書いてある。 

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3