Fail2Ban

Fail2Banはサーバに対するアクセス失敗ログや認証失敗ログを参照し、不要なアクセスを制限します。 Fail2Banを使用してそのような不要なアクセスをサーバに到達する前にファイアウォール等で遮断するのが一般的です。 しかし、このような遮断行為はある意味受け身的であり、やられっぱなしも癪です。 この記事は、遮断に加えて通報機能もFail2Banに持たせる事を目指します。

最近のクラウドサーバは、標準のサイバーレジリエンスでFail2Banがインストールされています。現在、syakesaba.comでは以下のサーバをFail2Ban対象としています。この設定は、sshd, postfix, dovecot, nginxの認証ログを参照し、一定期間、所定の回数の認証失敗ログの発生をトリガーにファイアウォールであるiptablesで認証失敗したホストを一定期間接続出来ないようにするものです。このファイル以外はOSのパッケージマネージャでインストールされた標準の設定ファイルを使用しています。

# /etc/fail2ban/jail.d/defaults-debian.conf
[DEFAULT]
banaction = iptables
banaction_allports = iptables[type=allports]
backend = systemd

[sshd]
enabled = true
backend = systemd

[postfix]
enabled = true
backend = systemd

[dovecot]
enabled = true
backend = systemd

[nginx-http-auth]
enabled = true
backend = systemd

今回は以下のサービスに対してBan対象のホストを通知するBanActionをsshdに追加します。

AbuseIPDB

AbuseIPDBはアカウントを持っている方なら誰でも悪意のあるIPアドレスを通報できるサービスです。

アカウント登録

AbuseIPDBホームページの右上のSign Upから登録を行います。FREEプランで登録します。

abuseipdb_plans.png

Warning

usernameはCommunityに公開されます。

abuseipdb_username.png

最後に、APIキーを取得しておきます。ログイン後のホームページの右上のMy APIメニューから取得が可能です。

abuseipdb_apikey.png

VirusTotal

VirusTotalもアカウントを持っている方なら誰でも悪意のあるIoCを通報できるサービスです。

アカウント登録

VirusTotalホームページの右上のSign Upから登録を行います。FREEプランで登録します。

Warning

First Name, Last Name, usernameすべてCommunityに公開されます。

virustotal_username.png

APIキーを取得しておきます。ログイン後のホームページの右上のAPI Keyメニューから取得が可能です。

Fail2Banとsshdの連携

Fail2Banはアクセスログ・認証ログファイルの更新を、inotifyシステムコールによって検出し、アクセス失敗ログ・認証失敗ログをFilterします。そして、一定回数以上失敗ログが発生したクライアントに対して一つ以上のActionを行うことが出来ます。そのActionにVirusTotalとAbuseIPDBへの通報を追加することで、世間一般に攻撃者のIPアドレスを周知し警戒する事が可能になります。

通常、Fail2Banは3つのコンポーネントで構成されます。

  • Jail: 監査対象を定義します。enabled = trueであれば監査が有効になります。独自のjail宣言はjail.localで宣言されます。
    • /etc/fail2ban/jail.d/*.conf
    • /etc/fail2ban/jail.local
  • Filter: 監査対象のメッセージ(ログ文字列など)から失敗ログを抽出する処理を定義します。主に構造化された正規表現です。
    • /etc/fail2ban/filter.d/*.conf
  • Action: 監査対象の失敗ログが観測された場合に実行する処理を定義します。
    • /etc/fail2ban/action.d/*.conf

私の環境ではsshdのFail2Banコンポーネントは以下で定義されてました。

  • Jail: /etc/fail2ban/jail.d/defaults-debian.conf
  • Filter: /etc/fail2ban/filter.d/sshd.conf
  • Action: /etc/fail2ban/action.d/iptables.conf

AbuseIPDB Action

AbuseIPDBは既にAction /etc/fail2ban/action.d/abuseipdb.conf が用意されているので、それを使用します。このファイルには以下の記述があります。

actionban = lgm=$(printf '%%.1000s\n...' "<matches>"); curl -sSf "https://api.abuseipdb.com/api/v2/report" -H "Accept: application/json" -H "Key: <abuseipdb_apikey>" --data-urlencode "comment=$lgm" --data-urlencode "ip=<ip>" --data "categories=<abuseipdb_category>"

この<...>の記法はPython “string interpolation” mechanismsに似た、プレイスホルダーに文字列を代入するテンプレート記法です。

これらの文字列は/etc/fail2ban/filter.d/sshd.confに定義されたfailregexによって失敗ログから生成されたり、事前に/etc/fail2ban/jail.localでユーザーが設定したりできます。

どのような文字列が生成されるかどうかは正規表現を読み解く必要がありますが、ログによって生成されるケース、されないケースがあるので、多くは使わない方が良いでしょう。今回のabuseipdb.confのactionbanで使われている文字列は以下のようになっております。

  • <matches>: AbuseIPDBに記録するコメント情報。個人情報が送信されないように、上書きを強く推奨。
  • <abuseipdb_apikey>: AbuseIPDBのAPIキー。
  • <ip>: クライアントIPアドレス。<HOST>の名前解決後のIPアドレス。
  • <abuseipdb_category>: AbuseIPDB上のカテゴリー番号のリスト。

これらはIntegrating AbuseIPDB with Fail2Ban - Automatically Report Bad IPsにも記述があります。APIKEYの箇所は自身のAPIキーに変更してください。

Actionの追加方法は非常にシンプルです。 /etc/fail2ban/jail.d/defaults-debian.conf を以下のように編集します。

# /etc/fail2ban/jail.d/defaults-debian.conf
[DEFAULT]
banaction = iptables
banaction_allports = iptables[type=allports]
backend = systemd

[sshd]
enabled = true
backend = systemd
# 追加
action = %(known/action)s
         abuseipdb[
            abuseipdb_apikey="APIKEY",
            abuseipdb_category="18,22",
            matches="Visit: https://www.syakesaba.com/"
        ]
bantime  = 86400
findtime  = 600
maxretry = 5

その後、Fail2Banをreloadし、RFC 5737 のテストネット (192.0.2.0/24、198.51.100.0/24、203.0.113.0/24) を使ってBanのテストを行います。

sudo systemctl reload fail2ban
sudo fail2ban-client set sshd banip 203.0.113.1

その後203.0.113.1のAbuseIPDBページを開いて、自分のレピュテーションが表示されているか確認します。

Warning

- Fail2Banで既にBanされているIPはFail2Banをreloadしても残ります。 `/var/lib/fail2ban/fail2ban.sqlite3`に不揮発な形でBanデータが保存されている為です。 - bantimeはAbuseIPDBのレートリミットの都合、900以上にしてください。

VirusTotal Action

VirusTotalはFail2BanにActionの登録はありませんので、Actionを自作する必要があります。今回自作するVirusTotalのActionでは以下の2つのAPIを使います。

Fail2Ban公式のAction定義に従って記述します。

virustotal_vote.local: Add a vote to an IP address API でレピュテーション

Add a vote to an IP address APIを叩く自作Actionを作成します。

[Init]
virustotal_apikey = 

virustotal_category = 

[Definition]
actionstart = 

actionstop = 

actioncheck = 

actionban = curl --request POST --url https://www.virustotal.com/api/v3/ip_addresses/<ip>/votes --header 'accept: application/json' --header 'content-type: application/json' --header 'x-apikey: <virustotal_apikey>' --data '{"data": {"type": "vote", "attributes":{"verdict": "<virustotal_category>"}}}'

actionunban = 

timeout = 300

これを /etc/fail2ban/action.d/virustotal_vote.local として保存しておきます。

virustotal_comment.local: Add a comment to an IP address API でコメント

Add a comment to an IP address API を叩く自作Actionを作成します。

[Init]
virustotal_apikey = 

[Definition]
actionstart = 

actionstop = 

actioncheck = 

actionban = curl --request POST --url https://www.virustotal.com/api/v3/ip_addresses/<ip>/comments  --header 'accept: application/json' --header 'content-type: application/json' --header 'x-apikey: <virustotal_apikey>' --data '{"data": {"type": "comment","attributes": {"text": "<matches>"}}}'

actionunban = 

timeout = 300

これを /etc/fail2ban/action.d/virustotal_comment.local として保存しておきます。

Warning

`matches`を使用していますが、これはそのまま使用せず、呼び出し元で変数を上書きすることを想定しています。

Fail2Ban Actionへの追加

Actionの追加方法はやはり、シンプルです。 /etc/fail2ban/jail.d/defaults-debian.conf を以下のように編集します。

# /etc/fail2ban/jail.d/defaults-debian.conf
[DEFAULT]
banaction = iptables
banaction_allports = iptables[type=allports]
backend = systemd

[sshd]
enabled = true
backend = systemd
# 追加
action = %(known/action)s
         abuseipdb[
            abuseipdb_apikey="APIKEY",
            abuseipdb_category="18,22",
            matches="Visit: https://www.syakesaba.com/"
        ]
         virustotal_vote[
            virustotal_apikey="APIKEY",
            virustotal_category="malicious"
        ]
         virustotal_comment[
            virustotal_apikey="APIKEY",
            matches="Visit: https://www.syakesaba.com/"
        ]
bantime  = 86400
findtime  = 600
maxretry = 5

その後、Fail2Banをreloadし、RFC 5737 のテストネット (192.0.2.0/24、198.51.100.0/24、203.0.113.0/24) を使ってBanのテストを行います。

sudo systemctl reload fail2ban
sudo fail2ban-client set sshd banip 203.0.113.2

その後203.0.113.2のVirusTotalページを開いて、自分のレピュテーションが表示されているか確認します。

まとめ

インターネットに公開されているサーバでFail2Banを動かして、自作のカスタムActionを使用して通報機能を実装しました。通報を行うことで、この世界のインターネットがより良いものになることに貢献できます。

通報結果画面イメージ

  • AbuseIPDB abuseipdb_reputated.png
  • VirusTotal virustotal_reputated.png

補足

追加のActionとは別で通常のBanが有効になっているかも確認してください.。

私の場合、通常のBanはiptablesによってなされますので以下で確認しました。

# IPv4
iptables -L -n
# IPv6
ip6tables -L -n

Fail2BanはIPv6も対応しています。

IPv6の場合、3fff::/20 が文書作成用(非活用)アドレスとして予約されていますので、それでテストが可能です。

sudo fail2ban-client set sshd banip 3fff::1
  • 3fff::1のVirusTotalのページを開いて、自分のレピュテーションが表示されているか確認します。
  • 3fff::1のAbuseIPDBのページを開いて、自分のレピュテーションが表示されているか確認します。