あなたのネットワークは嘘をついている
深夜にサーバーがSSHブルートフォース攻撃を受けてから、新しい環境を構築するたびにセキュリティは絶対に妥協できないものになった。ファイアウォール、fail2ban、鍵認証――当たり前の対策は一通り済ませていた。しかし長い間見て見ぬふりをしていた攻撃経路が、ネットワーク層のすぐそこに潜んでいる。ARPスプーフィングだ。静かで素早く、一般的な監視ツールにはまったく引っかからない。
ホームラボ、小規模オフィスネットワーク、あるいは共有ハイパーバイザー上のVPSを運用しているなら、ARPベースの攻撃は現実的な脅威だ。同じネットワークセグメントにいる攻撃者は、ファイアウォールのルールを一切引っかかることなく、すべてのトラフィックを自分のマシン経由に黙ってリダイレクトできる――認証情報の盗み見、パケットへのペイロード注入、パケットドロップまで自由にできてしまう。
以下では、攻撃の仕組みを解説した上で、arpwatchによる検出環境の構築と、arptablesを使った事前ブロックの方法を紹介する。
ARPスプーフィングが実際に何をするのか
ARP(Address Resolution Protocol)は、ローカルネットワーク上でIPアドレスをMACアドレスに対応させるプロトコルだ。自分のマシンが192.168.1.1に接続しようとすると、「192.168.1.1を持っているのは誰だ?」というARPリクエストをブロードキャストする。ルーターが自分のMACアドレスで応答し、マシンはそのマッピングをキャッシュする。
問題は、ARPに認証機能がまったくないことだ。ネットワーク上の誰でも、任意のIPを自分のMACにマッピングする偽のARP応答を送れる。マシンは確認も検証もせずにARPキャッシュを更新してしまう。
攻撃の流れはこうだ:
- 攻撃者が被害者に偽のARP応答を送る:「192.168.1.1(ゲートウェイ)のMACはAA:BB:CC:DD:EE:FFだ」
- 攻撃者は同時にゲートウェイにも伝える:「192.168.1.50(被害者)のMACはAA:BB:CC:DD:EE:FFだ」
- すべてのトラフィックが攻撃者のマシンを経由する――古典的な中間者(Man-in-the-Middle)の状態だ
- 攻撃者はパケットを転送して接続を維持するため、被害者は何も異常に気づかない
arpspoof、ettercap、bettercapといったツールを使えば、30秒以内にこれを実行できる。50台のマシンが動くオフィスネットワークでは、攻撃者がbettercapを起動してから1分以内にHTTP認証情報の取得が始まる。仕組みを理解すれば、検出と防止も同じくらい素早く展開できる。
arpwatchで検出環境を構築する
arpwatchはARPトラフィックを監視し、MACとIPのペアリングが変わるたびに警告を発する。既知の対応関係のデータベースを管理し、予期しない変更にフラグを立てる――まさにARPスプーフィングが引き起こす変化を捉えられる。
インストール
# Debian/Ubuntu
sudo apt update && sudo apt install arpwatch -y
# CentOS/RHEL/Rocky
sudo dnf install arpwatch -y
# Arch Linux
sudo pacman -S arpwatch
基本設定
設定の大部分は設定ファイルではなくサービスのフラグで行う。まずネットワークインターフェース名を確認しよう:
ip link show
次に、監視するインターフェースをサービス設定に記述する:
# Debian/Ubuntuの場合、デフォルトファイルを編集する
sudo nano /etc/default/arpwatch
# インターフェースを設定する(eth0は自分の環境に合わせて変更)
IFACE="eth0"
ARPWATCH_OPTS="-N -p"
-Nフラグはメールアラートを無効にする(アラートは別途処理する)。-pはインターフェースをプロミスキャスモードにしない設定で、ブロードキャストドメイン全体ではなく自分のマシンのARPアクティビティだけを監視したい場合に便利だ。
メールアラートをネイティブに使いたい場合は、システムのMTAを設定した上で-Nフラグを外す。arpwatchは「flip flop」イベントのたびにメールを送ってくれる。
arpwatchの起動と自動起動設定
sudo systemctl enable arpwatch
sudo systemctl start arpwatch
sudo systemctl status arpwatch
arpwatchのログを読む
arpwatchはsyslogに書き込む。把握しておくべきイベントタイプは以下の通り:
# リアルタイムでイベントを監視する
sudo journalctl -u arpwatch -f
# またはsyslogを直接確認する
sudo tail -f /var/log/syslog | grep arpwatch
注意すべき主要なイベント:
- flip flop — あるIPのMACアドレスが変わり、また元に戻った。ARPスプーフィングの典型的なシグネチャだ。
- changed ethernet address — 既知のIPが別のMACにマッピングされた。正当なデバイス交換の可能性もあるが、攻撃が進行中かもしれない。
- new activity — 既知のホストが非アクティブ状態から再び現れた。
- new station — 新しいデバイスがネットワークに参加した。
実際の攻撃時のログエントリはこのようになる:
May 21 03:14:22 myserver arpwatch: flip flop 192.168.1.1 aa:bb:cc:dd:ee:ff (00:11:22:33:44:55) eth0
意味:ゲートウェイのMACが00:11:22:33:44:55からaa:bb:cc:dd:ee:ffに切り替わった。即座に調査が必要だ。
arptablesでARP攻撃をブロックする
検出は何かが起きたことを教えてくれる。arptablesはパケットレベルでARPルールを強制できる――正当なMACとIPのペアをホワイトリストに登録し、それ以外をすべてドロップするのだ。
arptablesのインストール
# Debian/Ubuntu
sudo apt install arptables -y
# CentOS/RHEL
sudo dnf install arptables -y
現在のルールを確認する
sudo arptables -L -v
静的ARPエントリ――最もシンプルな防御
arptablesを触る前に、まず静的ARPエントリを検討しよう。ARPキャッシュにゲートウェイのMACをハードコードすることで、スプーフィングされた応答が上書きできなくなる:
# まずゲートウェイの本当のMACを確認する
arp -n 192.168.1.1
# 永続的な静的エントリを追加する
sudo arp -s 192.168.1.1 00:11:22:33:44:55
# PERMとしてマークされていることを確認する
arp -n
出力にゲートウェイエントリの横にPERMが表示されるはずだ。単一ゲートウェイの/24フラットネットワークでは、このひと手間だけで最も一般的なMITMシナリオをほぼ完全に防げる。
再起動後も設定を維持するには、/etc/ethersとarp -fを使う:
# /etc/ethersのフォーマット:MAC IP
echo "00:11:22:33:44:55 192.168.1.1" | sudo tee -a /etc/ethers
# 起動時に読み込む――/etc/rc.localまたはsystemdサービスに追加する
sudo arp -f /etc/ethers
arptablesでルールを強制する
ネットワークトポロジーが固定されているサーバーや管理下のインフラでは、arptablesで精密なコントロールができる。既知のゲートウェイからのARPのみを許可し、それ以外をドロップする:
# 正規のゲートウェイからのARPのみを許可する
# 実際のゲートウェイのMACとIPに置き換えること
sudo arptables -A INPUT --source-mac 00:11:22:33:44:55 --source-ip 192.168.1.1 -j ACCEPT
# そのゲートウェイIPを名乗る他のすべてのARP応答をドロップする
sudo arptables -A INPUT --source-ip 192.168.1.1 -j DROP
本物のMACからは受け入れ、そのIPを名乗る他のものはすべてドロップする。攻撃者がスプーフィングパケットを送り続けても、カーネルが無視するだけだ。
自分のマシンがMITMの中継点として使われないようにするため、送信ARPも制限しよう:
# 自分のMACからのみARPを送信する
MY_MAC=$(cat /sys/class/net/eth0/address)
sudo arptables -A OUTPUT --source-mac ! $MY_MAC -j DROP
ルールの保存と復元
# ルールを保存する
sudo arptables-save > /etc/arptables.rules
# 起動時にルールを復元する――/etc/rc.localまたはsystemdユニットに追加する
sudo arptables-restore < /etc/arptables.rules
シンプルな検出スクリプト
軽量なマシンでフルデーモンを動かしたくない場合は、このスクリプトをcronジョブに登録しよう。2分ごとにARPテーブルをスナップショットして、変化があれば警告を出す:
#!/bin/bash
# arp_monitor.sh — ARPキャッシュの変化を警告する
SNAPSHOT_FILE="/tmp/arp_snapshot"
CURRENT=$(arp -n | awk 'NR>1 {print $1, $3}')
if [ ! -f "$SNAPSHOT_FILE" ]; then
echo "$CURRENT" > "$SNAPSHOT_FILE"
echo "ベースラインのARPスナップショットを保存しました。"
exit 0
fi
DIFF=$(diff <(cat "$SNAPSHOT_FILE") <(echo "$CURRENT"))
if [ -n "$DIFF" ]; then
echo "[警告] $(date)にARPテーブルが変化しました:"
echo "$DIFF"
# Telegramやメールによるアラートはここでコメントアウトを外して追加する
fi
echo "$CURRENT" > "$SNAPSHOT_FILE"
# 実行権限を付与してcronでスケジュールする
chmod +x /usr/local/bin/arp_monitor.sh
(crontab -l; echo "*/2 * * * * /usr/local/bin/arp_monitor.sh >> /var/log/arp_monitor.log 2>&1") | crontab -
すべてを組み合わせる
共有ネットワーク上にあるLinuxマシンで私が実際に採用している多層構成はこうだ:
- 静的ARPエントリ――ゲートウェイ、DNSサーバー、NFSサーバーなど重要なホスト向け。即時保護でオーバーヘッドゼロ
- arpwatchをサービスとして常駐――継続的な監視で、あらゆる異常をsyslogに記録
- arptablesルール――ネットワークトポロジーが固定・既知のサーバー向け
- ARPモニタリングcronジョブ――デーモンが過剰なほど軽量なマシン向け
環境に見合った数の層を重ねよう。層が多いほど、攻撃者は長時間こっそり潜伏できなくなる。
最後にひとつ確認しておく価値があること:あなたのスイッチはDynamic ARP Inspection(DAI)に対応しているか?Cisco Catalyst、HP ProCurve、そして多くの管理対応エンタープライズスイッチは対応している。DAIはDHCPスヌーピングバインディングテーブルに照らしてARPパケットをハードウェアレベルで検証する。
スプーフィングされた応答はホストに届く前にドロップされる。対応ハードウェアがあるなら有効にしよう。スイッチ層のDAIとホスト上のarpwatch・静的ARPエントリを組み合わせることで、Linuxネットワークで現実的に直面するほぼすべての攻撃経路を塞げる。

