detecting-port-scanning-with-fail2ban について
Fail2banでログからポートスキャンやブルートフォース攻撃を検出し、ファイアウォールで送信元 IP を遮断する手順を解説するセキュリティスキルです。サーバー運用・セキュリティ担当者向けに、フィルター作成から検証、監視まで扱います。
主な機能
- 01ログからスキャンやブルートフォースを検出
- 02Fail2ban の jail とフィルターを設定
- 03iptables または nftables で IP を遮断
- 04フィルターのテストと遮断状況の確認
活用シーン
- 01公開サーバーへの自動スキャンを遮断
- 02SSH、HTTP、FTP へのブルートフォース対策
- 03組織固有のログパターンに応じた検出ルール作成
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill detecting-port-scanning-with-fail2banインストール後、Claude Code で/detecting-port-scanning-with-fail2banを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
LICENSEreferences/api-reference.mdscripts/agent.py詳細
Fail2ban によるポートスキャンの検出
使用する場面
- インターネットに公開されているサーバーに対してポートスキャンを行う IP アドレスを自動的にブロックする
- SSH、HTTP、FTP などのサービスをブルートフォース攻撃から守るため、IP アドレスを自動的に禁止する
- ログファイル内の組織固有の攻撃パターンを検出するカスタムフィルターを作成する
- IDS/IPS が詳細な分析を行う前に、自動スキャンボットによるノイズを減らす
- ネットワーク監視にホストベースの自動応答を追加して、多層防御を実装する
単独のネットワークセキュリティ制御として、複数の送信元 IP アドレスからの分散攻撃に対する防御として、または適切なファイアウォールルールやネットワークセグメンテーションの代替としては使用しないでください。
前提条件
- Fail2ban 0.11 以降がインストールされていること(
fail2ban-client --version) - iptables/nftables を操作するための root/sudo アクセス権
- 解析可能なログファイル(syslog、auth.log、access.log)に接続試行を記録するサービス
- ホストファイアウォールとして iptables または nftables がインストールされ、動作していること
- 任意:禁止イベントのメール通知用 SMTP サーバー
ワークフロー
ステップ 1:Fail2ban をインストールして設定する
# Install Fail2ban
sudo apt install -y fail2ban
# Create local configuration (never edit jail.conf directly)
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
# Configure global defaults
sudo tee /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
# Ban duration (1 hour default, escalates for repeat offenders)
bantime = 3600
# Detection window
findtime = 600
# Max failures before ban
maxretry = 5
# Ban action using iptables
banaction = iptables-multiport
banaction_allports = iptables-allports
# Email notifications
destemail = [email protected]
sender = [email protected]
mta = sendmail
action = %(action_mwl)s
# Ignore internal networks
ignoreip = 127.0.0.1/8 ::1 10.10.0.0/16
# Use systemd journal backend where available
backend = systemd
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 7200
findtime = 300
[sshd-ddos]
enabled = true
port = ssh
filter = sshd-ddos
logpath = /var/log/auth.log
maxretry = 6
bantime = 3600
EOF
ステップ 2:カスタムのポートスキャン検出フィルターを作成する
# Create iptables logging rule for dropped connections
sudo iptables -N PORTSCAN
sudo iptables -A PORTSCAN -j LOG --log-prefix "PORTSCAN_DETECTED: " --log-level 4
sudo iptables -A PORTSCAN -j DROP
# Log SYN packets to closed ports (indicates scanning)
sudo iptables -A INPUT -p tcp --tcp-flags SYN,ACK,FIN,RST SYN -m state --state NEW \
-m recent --name portscan --set
sudo iptables -A INPUT -p tcp --tcp-flags SYN,ACK,FIN,RST SYN -m state --state NEW \
-m recent --name portscan --rcheck --seconds 10 --hitcount 20 -j PORTSCAN
# Create Fail2ban filter for port scanning
sudo tee /etc/fail2ban/filter.d/portscan.conf << 'EOF'
[Definition]
# Match iptables port scan log entries
failregex = PORTSCAN_DETECTED: .* SRC=<HOST> DST=\S+ .* DPT=\d+
ignoreregex =
datepattern = {^LN-BEG}
EOF
# Create Fail2ban filter for Nmap detection via kernel logs
sudo tee /etc/fail2ban/filter.d/nmap-scan.conf << 'EOF'
[Definition]
# Detect rapid connection attempts to multiple ports from same source
failregex = kernel: \[.*\] PORTSCAN_DETECTED: .* SRC=<HOST>
iptables: .* PORTSCAN .* SRC=<HOST>
ignoreregex =
datepattern = {^LN-BEG}
EOF
# Create filter for HTTP scanning/probing
sudo tee /etc/fail2ban/filter.d/http-scan.conf << 'EOF'
[Definition]
# Detect scanners probing for common vulnerabilities
failregex = ^<HOST> .* "(GET|POST|HEAD) /(wp-login|wp-admin|phpmyadmin|admin|.env|xmlrpc|wp-content/uploads).*" (403|404|444)
^<HOST> .* "(GET|POST) /.*\.(php|asp|aspx|jsp|cgi)\?.*" (403|404)
^<HOST> .* "() .*" 400
^<HOST> .* "(GET|POST) /.*" 400
ignoreregex =
datepattern = {^LN-BEG}
EOF
ステップ 3:ポートスキャン用の Jail を設定する
# Add port scan jails to jail.local
sudo tee -a /etc/fail2ban/jail.local << 'EOF'
[portscan]
enabled = true
filter = portscan
logpath = /var/log/kern.log
maxretry = 10
findtime = 60
bantime = 86400
banaction = iptables-allports
action = %(action_mwl)s
[nmap-scan]
enabled = true
filter = nmap-scan
logpath = /var/log/kern.log
maxretry = 5
findtime = 30
bantime = 86400
banaction = iptables-allports
action = %(action_mwl)s
[http-scan]
enabled = true
filter = http-scan
logpath = /var/log/nginx/access.log
maxretry = 10
findtime = 300
bantime = 3600
banaction = iptables-multiport
port = http,https
[recidive]
enabled = true
filter = recidive
logpath = /var/log/fail2ban.log
bantime = 604800
findtime = 86400
maxretry = 3
banaction = iptables-allports
action = %(action_mwl)s
EOF
ステップ 4:高度な禁止アクションを設定する
# Create custom action that blocks and sends webhook notification
sudo tee /etc/fail2ban/action.d/iptables-webhook.conf << 'EOF'
[Definition]
actionstart = <iptables> -N f2b-<name>
<iptables> -A f2b-<name> -j RETURN
<iptables> -I <chain> -p <protocol> -j f2b-<name>
actionstop = <iptables> -D <chain> -p <protocol> -j f2b-<name>
<iptables> -F f2b-<name>
<iptables> -X f2b-<name>
actioncheck = <iptables> -n -L <chain> | grep -q 'f2b-<name>[ \t]'
actionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>
curl -s -X POST "<webhook_url>" \
-H "Content-Type: application/json" \
-d '{"text":"[Fail2ban] Banned <ip> from <name> jail (failures: <failures>)"}'
actionunban = <iptables> -D f2b-<name> -s <ip> -j <blocktype>
[Init]
chain = INPUT
blocktype = DROP
webhook_url = https://hooks.slack.com/services/XXXX/YYYY/ZZZZ
EOF
# Create escalating ban action for repeat offenders
sudo tee /etc/fail2ban/action.d/escalating-ban.conf << 'EOF'
[Definition]
actionban = <iptables> -I f2b-<name> 1 -s <ip> -j DROP
echo "$(date) BAN <ip> jail=<name> failures=<failures> bantime=<bantime>" >> /var/log/fail2ban-bans.log
actionunban = <iptables> -D f2b-<name> -s <ip> -j DROP
echo "$(date) UNBAN <ip> jail=<name>" >> /var/log/fail2ban-bans.log
EOF
ステップ 5:検出をテストして検証する
# Restart Fail2ban
sudo systemctl restart fail2ban
# Verify jails are active
sudo fail2ban-client status
sudo fail2ban-client status sshd
sudo fail2ban-client status portscan
# Test the port scan filter with a regex check
sudo fail2ban-regex /var/log/kern.log /etc/fail2ban/filter.d/portscan.conf
# Test the HTTP scan filter
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/http-scan.conf
# Simulate a port scan from a test machine (authorized)
# From the test machine:
nmap -sS -p 1-1000 <target_ip>
# Verify the scanner gets banned
sudo fail2ban-client status portscan
# Should show the test IP in the banned list
# Check iptables for the ban rule
sudo iptables -L f2b-portscan -n
# Unban the test IP
sudo fail2ban-client set portscan unbanip <test_ip>
ステップ 6:監視して保守する
# View real-time ban activity
sudo tail -f /var/log/fail2ban.log | grep -E "Ban|Unban"
# Generate daily summary report
sudo tee /usr/local/bin/fail2ban-report.sh << 'SCRIPT'
#!/bin/bash
echo "=== Fail2ban Daily Report $(date) ==="
echo ""
echo "Active Jails:"
sudo fail2ban-client status | grep "Jail list"
echo ""
echo "Currently Banned IPs:"
for jail in $(sudo fail2ban-client status | grep "Jail list" | sed 's/.*://;s/,//g'); do
count=$(sudo fail2ban-client status "$jail" | grep "Currently banned" | awk '{print $NF}')
if [ "$count" -gt 0 ]; then
echo " $jail: $count banned"
sudo fail2ban-client status "$jail" | grep "Banned IP"
fi
done
echo ""
echo "Last 24 hours - Ban count by jail:"
grep "Ban " /var/log/fail2ban.log | grep "$(date +%Y-%m-%d)" | awk '{print $NF}' | sort | uniq -c | sort -rn
SCRIPT
chmod +x /usr/local/bin/fail2ban-report.sh
# Schedule daily report
echo "0 8 * * * root /usr/local/bin/fail2ban-report.sh | mail -s 'Fail2ban Report' [email protected]" | sudo tee /etc/cron.d/fail2ban-report
# Persist iptables rules across reboots
sudo apt install iptables-persistent
sudo netfilter-persistent save
主な概念
| 用語 | 定義 |
|---|---|
| Jail | 特定のサービスに対して、フィルター(検出対象)、アクション(実行する処理)、パラメーター(しきい値、時間)を組み合わせる Fail2ban の設定単位です |
| フィルター | Fail2ban がログファイルに適用し、認証の失敗、スキャン、その他の悪意ある活動を識別する正規表現パターンです |
| Recidive Jail | Fail2ban 自身のログを監視するメタ Jail です。複数回禁止された IP に対して、禁止期間を段階的に延長します |
| Find Time | Fail2ban が一致するログエントリーを数える時間枠(秒)です。findtime 内に maxretry 回失敗すると、禁止が実行されます |
| 禁止アクション | IP が禁止されたときに実行されるコマンドまたはスクリプトです。通常はファイアウォールルールを追加しますが、Webhook、SIEM アラート、ブロックリストの更新にも拡張できます |
| 除外 IP | 信頼できるネットワークや監視システムが締め出されないよう、決して禁止しない IP アドレスまたは CIDR 範囲の許可リストです |
ツールとシステム
- Fail2ban 0.11 以降:ログを解析する侵入防止フレームワークです。任意のログファイルに対するパターンマッチングに基づいて IP アドレスを禁止します
- iptables/nftables:Linux カーネルのファイアウォールです。Fail2ban の禁止アクションが、ネットワーク層で問題のある IP アドレスをブロックするために使用します
- fail2ban-regex:本番環境に導入する前に、実際のログファイルに対するフィルターの正規表現を検証するテスト用ユーティリティです
- fail2ban-client:Jail の状態の照会、IP の手動での禁止/解除、設定の再読み込みを行うコマンドライン管理ツールです
- rsyslog/syslog-ng:Fail2ban が攻撃検出のために監視するログファイルを生成するシステムログデーモンです
よくあるシナリオ
シナリオ:自動スキャンから公開ウェブサーバーを防御する
コンテキスト:ある企業は、脆弱性のあるパス(/wp-admin、/phpmyadmin、/.env)を探るボットから、毎日数千件の自動スキャンを受ける公開ウェブサーバーを運用しています。セキュリティチームは、正当なトラフィックを許可しながら、スキャナーを自動的にブロックしたいと考えています。サーバーでは Ubuntu 22.04 上で Nginx が稼働しています。
アプローチ:
- Fail2ban をインストールし、スキャンパターン(既知の脆弱性パスへの 404/403 レスポンス)がないか Nginx のアクセスログを監視するよう設定します
- 一般的なスキャナーのシグネチャと脆弱性を探る URI に一致する、カスタムの
http-scanフィルターを作成します - 5 分間の findtime 内で maxretry を 10 に設定し、初回の違反には bantime を 1 時間に設定します
- recidive jail を有効にし、再犯者の禁止期間を 7 日間に延長します
- 禁止処理の状況をリアルタイムで確認できるよう、Slack への Webhook 通知を設定します
- ポートスキャンを検出するため、閉じたポートへの SYN パケットを記録する iptables ルールを追加します
- 禁止した IP、攻撃パターン、地理的な分布を表示する日次レポートスクリプトを作成します
注意点:
- maxretry を低く設定しすぎる(例:1~2)と、URL を入力し間違えた正当なユーザーまで禁止されることがあります
- ヘルスチェックによってフィルターが作動する可能性がある監視システム(Nagios、UptimeRobot)をホワイトリストに登録しないこと
- iptables ルールを永続化し忘れると、再起動後にすべての禁止設定が失われます
- デプロイ前に fail2ban-regex でフィルターをテストしないと、一致が得られなかったり、誤検知が過剰に発生したりします
出力形式
## Fail2ban Port Scan Defense Report
**Server**: web-prod-01 (203.0.113.50)
**Reporting Period**: 2024-03-15 00:00 to 2024-03-16 00:00 UTC
### Active Jails
| Jail | Filter | Max Retry | Ban Time | Currently Banned |
|------|--------|-----------|----------|------------------|
| sshd | sshd | 3 | 2 hours | 12 IPs |
| portscan | portscan | 10 | 24 hours | 47 IPs |
| http-scan | http-scan | 10 | 1 hour | 89 IPs |
| recidive | recidive | 3 | 7 days | 8 IPs |
### 24-Hour Summary
- Total ban events: 347
- Unique IPs banned: 156
- Top attacking country: CN (67 IPs), RU (34 IPs), US (21 IPs)
- Most targeted service: HTTP scanning (214 bans)
- Recidive escalations: 8 IPs banned for 7 days
### Top 5 Banned IPs
| IP Address | Jail | Ban Count | First Seen | Last Seen |
|------------|------|-----------|------------|-----------|
| 45.33.32.156 | portscan | 12 | 00:15 | 23:47 |
| 198.51.100.23 | http-scan | 8 | 02:30 | 18:22 |
| 203.0.113.100 | sshd | 6 | 05:12 | 21:33 |
コメント
Markdown 対応