概要
- Apache
- Mod_Security
- テキストファイル
連携によるWeb防御『ONE OUTS』3回目。
ここでは応用編として、筆者の具体的なチューニングや追加設定などをご紹介します。
Cron設定
前項で説明したone_outs.sh
。これは、筆者はCron化して自動運用しています。そのため、スクリプトは以下のように簡素化しています。
#!/bin/bash
#
# ONE OUTS System - IP Blacklist Auto-Generator (for cron)
#
# このスクリプトは、Tor出口ノードのリストとApacheのエラーログから
# 不審なIPアドレスを抽出し、ModSecurity用のブラックリストを自動生成します。
# cronなどで定期的に実行することを想定しています。
#
# === 変数の定義 ===
# --- 基本設定 ---
SCRIPT_BASE_DIR="/usr/local/scripts/security"
APACHE_LOG_DIR="/var/log/apache2"
MODSEC_BLACKLIST_FILE="/etc/modsecurity/ip-blacklist.txt"
# --- 除外設定 ---
EXCLUDE_IPS_FILE="${SCRIPT_BASE_DIR}/conf/exclude_ips.txt"
# --- 中間ファイル設定 ---
TOR_EXIT_LIST_RAW="${SCRIPT_BASE_DIR}/work/tor_exit_nodes_raw.txt"
TOR_EXIT_LIST_IPS="${SCRIPT_BASE_DIR}/work/tor_exit_nodes_ips.txt"
SUSPICIOUS_IPS_DAILY="${SCRIPT_BASE_DIR}/work/suspicious_ips_daily.txt"
SUSPICIOUS_IPS_ALL="${SCRIPT_BASE_DIR}/work/suspicious_ips_all.txt"
# === 処理の開始 ===
# 1. Tor出口ノードリストの取得
curl -s -o "${TOR_EXIT_LIST_RAW}" "https://check.torproject.org/exit-addresses"
if [ $? -ne 0 ]; then
# エラーが発生した場合は syslog に記録
logger "ONE OUTS Script Error: Failed to download Tor exit node list."
exit 1
fi
awk '/^ExitAddress/ {print $2}' "${TOR_EXIT_LIST_RAW}" | sort -u > "${TOR_EXIT_LIST_IPS}"
# 2. Apacheエラーログからの不審IP抽出
grep "ModSecurity" "${APACHE_LOG_DIR}/error.log" | \
grep -o -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | \
sort -u > "${SUSPICIOUS_IPS_DAILY}"
touch "${SUSPICIOUS_IPS_ALL}"
cat "${SUSPICIOUS_IPS_ALL}" "${SUSPICIOUS_IPS_DAILY}" | sort -u > "${SUSPICIOUS_IPS_ALL}.tmp" && mv "${SUSPICIOUS_IPS_ALL}.tmp" "${SUSPICIOUS_IPS_ALL}"
# 3. ブラックリストの生成
# 変更前のチェックサムを保存
PREV_CHECKSUM=$(md5sum "${MODSEC_BLACKLIST_FILE}" | awk '{print $1}')
# Torリストと不審IPリストを結合して一時ファイルを作成
cat "${TOR_EXIT_LIST_IPS}" "${SUSPICIOUS_IPS_ALL}" | sort -u > "${MODSEC_BLACKLIST_FILE}.tmp"
# 4. 除外IPの削除
if [ -f "${EXCLUDE_IPS_FILE}" ]; then
grep -v -f "${EXCLUDE_IPS_FILE}" "${MODSEC_BLACKLIST_FILE}.tmp" > "${MODSEC_BLACKLIST_FILE}"
else
mv "${MODSEC_BLACKLIST_FILE}.tmp" "${MODSEC_BLACKLIST_FILE}"
fi
rm -f "${MODSEC_BLACKLIST_FILE}.tmp" # -f オプションでファイルがなくてもエラーにならないように
# 変更後のチェックサムを取得
POST_CHECKSUM=$(md5sum "${MODSEC_BLACKLIST_FILE}" | awk '{print $1}')
# 5. ファイルに変更があった場合のみApacheをリロード
if [ "${PREV_CHECKSUM}" != "${POST_CHECKSUM}" ]; then
logger "ONE OUTS Script: Blacklist updated. Reloading Apache."
systemctl reload apache2.service
fi
exit 0
これをcrontabで設定。(その際にはchmod +x one_outs.sh
を忘れないように)
# ONE OUTS
0 4 * * * sleep $(shuf -i 0-59 -n 1)m && /home/hoverbucks/script/server/one_outs.sh
として実行します。この、実行分をランダムにするのは、リストが更新されるというトリガーをつかみにくくするためです。
スローロリス攻撃への対処
この、ONE_OUTSの自動実行を行った頃、サーバのレスポンスが悪くなると言う状況を確認しました。以下のようなログを確認(アクセス元などはダミーに置き換えています)
# [クライアントIP] [タイムスタンプ]
# --- 攻撃検知 (1/2): カスタムルールが矛盾したConnectionヘッダーを検知 ---
[Mon Oct 20 11:30:05 2025] [security2:error] [client 198.51.100.201] ModSecurity: Warning. ... [id "10001"] [msg "[CUSTOM RULE] Contradictory Connection header, possible Slowloris probe."] [hostname "your-domain.com"] [uri "/search?query=some-long-query"]
# --- 攻撃検知 (2/2): CRSの標準ルールも同じ異常を検知 (スコア+3) ---
# data "keep-alive, close" の部分で、実際にどのようなデータが送られてきたかを確認できます。
[Mon Oct 20 11:30:05 2025] [security2:error] [client 198.51.100.201] ModSecurity: Warning. ... [id "920210"] [msg "Multiple/Conflicting Connection Header Data Found"] [data "keep-alive, close"] [severity "WARNING"] [hostname "your-domain.com"] [uri "/search?query=some-long-query"]
# --- 最終報告: 合計スコアとブロックに至らなかった状況を記録 ---
# この攻撃単体ではスコアが3のため、ブロックしきい値の5には達していません。
# 他の攻撃と組み合わさった場合に、ブロックの判断材料となります。
[Mon Oct 20 11:30:05 2025] [security2:error] [client 198.51.100.201] ModSecurity: Warning. ... [id "980170"] [msg "Anomaly Scores: (Inbound Scores: blocking=3, detection=3, ... threshold=5)"] [hostname "your-domain.com"] [uri "/search?query=some-long-query"]
これは典型的なスローロリス攻撃。
「Connectionヘッダーにkeep-aliveとcloseを同時に送信する」ことで、コネクションを矛盾させリソースを奪い最終的に枯渇を狙うというのは、攻撃者がCRS(Core Rule Set)に基づいた防御を行っていると確認した際/または単純な威力偵察の際によく使う手です。
漫画『ドリフターズ』に曰く
「こりゃ堕とせんと思ったら
その時から目的は変わるのよ
占領からいやがらせに変わる」
この、いやがらせ目的のため、自分のサーバのリソースが奪われるという状況は見過ごせません。以下のような処置を設けます。
固定ページ: 12
コメントを残す