Skip to content

Instantly share code, notes, and snippets.

@hdais
Last active November 19, 2021 07:38
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hdais/49e28d9777fb36a4c3ec5e74f9666690 to your computer and use it in GitHub Desktop.
Save hdais/49e28d9777fb36a4c3ec5e74f9666690 to your computer and use it in GitHub Desktop.
DNSフラグメント攻撃の権威サーバ側の対策について

DNSフラグメント攻撃に対する権威サーバ側の緩和策について

TL;DR

背景

DNSフラグメント攻撃についてはこちらを参照されたい。

ここで、権威サーバからの応答を強制的かつ攻撃者の任意の位置でフラグメントさせるために、攻撃者が偽のICMPv4 type 3 code 4 (destination Unreachable, fragmentation needed and DF set、以下簡単に ICMPv4 Packet TooBig) を権威サーバに投げつけることが攻撃成立の一つの要素となっている 。厳密にはそうでないケースもあるが、現時点で知られている限りほとんどのケースで必要である。

DNS権威サーバがLinuxの場合、デフォルト設定のIPv4 UDP ソケットはその偽ICMPv4 Packet TooBigメッセージを容易に受け入れ、送信するUDPパケット (DNS応答) をフラグメントして送信してしまう。

Linuxで動作するDNS権威サーバのフラグメント攻撃緩和策

Linux Kernel 3.15 から、新しいソケットオプションIP_PMTUDISC_OMIT が実装された。

このオプション有効にしたソケットは、ICMPv4 Packet TooBigメッセージを無視し、インタフェースMTU (ほとんどの場合、Ethenet MTUである 1500バイト) を超えた場合のみ送信時にフラグメントが行われる。すなわち、偽のICMPv4 Packet Toobigメッセージに騙されることがなくなり、これがフラグメント攻撃に対する緩和策となる。

このオプションが有効となるには、Linux カーネルのバージョンが 3.15以降であることの他、権威サーバソフトウェア側でも本オプションを IPv4 UDPソケットに対して有効にするコードが必要がある。有効化は簡単で、ソケットに対して setsockopt()するだけである。下記は、権威サーバ内で有効化するコードのイメージである。

#include <netinet/in.h>

#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_OMIT)
    int action_omit = IP_PMTUDISC_OMIT;
    setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action_omit, sizeof(action_omit));
#endif

IP_PMTUDISC_OMIT が有効になる DNS権威サーバ実装

以上の権威サーバのバージョンを、

  • Linux 3.15 以降

環境でビルドして動作させれば、自動的にフラグメント攻撃緩和策が有効となる。特別な設定やコンパイルオプションも不要である。

Red Hat Enterprise Linuxについて

RHEL6 のカーネルは Linux 2.6.32ベース、RHEL7は3.10ベースと古く、カーネルのバージョンだけ見れば上記の権威サーバでも緩和策が有効にならないのだが、実は RHEL6/7に付属している Red Hat版Linuxカーネルには IP_PMTUDISC_OMIT 機能がバックポートされている(3.10.0-217.el7 / 2.6.32-525.el6)。

残念なことに、Red Hat は RHELのglibcヘッダに IP_PMTUDISC_OMIT マクロをバックポートし忘れており、ごく最近までRHEL6,7で対応済権威サーバをコンパイルしても、本機能が有効とならなかった (上記のコードで IP_PMTUDISC_OMIT マクロが定義されていないと setsockopt()できないことに注意)。

RHEL 7.7 以降

この glibc における IP_PMTUDISC_OMIT 未定義の問題は RHEL 7.7 (glibc-2.17-284.el7)で修正された。

したがって、RHEL 7.7 以降の環境で、上記権威サーバの新バージョン (BINDなら 9.9.10, 9.11.1, 9.12, 9.13 以降) をビルド・実行すれば緩和策が有効になる。特別なコンパイルオプションも不要である。

なお、RHEL 7に付属するパッケージの BIND9 は 9.9.4ベースであるため、本緩和策は無効である。有効となるバージョンをソースからビルドする必要がある。  なお、RHEL 7.7付属の BINDパッケージは 9.11.4 ベースに変更されたため (RHEL 7.6まではBIND 9.9.4ベース)、緩和策が有効となっている。

RHEL 7.6以前でも緩和策を有効にする

上記 glibcの問題で 緩和策が有効にならない RHEL のバージョンでも、

  • RHEL 6.7 以降 (kernel 2.6.32-525.el6)
  • RHEL 7.1 以降 (kernel 3.10.0-217.el7)

ならば、カーネル自体には本機能が入っているため、裏技的であるが緩和策を有効にすることができる。DNSサーバをビルドする際の ./configure 実行時に、Cコンパイラに対して強制的に IP_PMTUDISC_OMIT マクロを定義させるようにする。

$ ./configure CFLAGS=-DIP_PMTUDISC_OMIT=5

ほかのOSではどうか?

IP_PMTUDISC_OMIT はLinuxのソケットオプションであるが、ほかのOSではどうか。

FreeBSD の IPv4 UDPソケットは、デフォルトで Linux の IP_PMTUDISC_OMIT 相当の動作となっており、偽ICMPv4メッセージに騙されないため本緩和策が有効 (権威サーバ側の対応も不要) である。

Linux / FreeBSD以外のOSの状況は不明である。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment