Router Advertisement Spoofing

ルーター広告スプーフィング

2010年6月29日

目次

  1. はじめに
  2. 概要
  3. 構成
  4. 実験
  5. 対策
  6. おわりに

はじめに

  以前、IPv6の近隣探索スプーフィングについて記事を書きました。その記事の中で、ローカルネットに潜む攻撃者は、同じサブネット上の他のホストがデフォルトルーターに向けて送信するEthernetフレームを横取りすることができると述べました。しかし、その記事の中で述べた方法では正当なデフォルトルーターが正しく動作する限り、長い時間継続してフレームを横取りすることができませんでした。これは管理者にとって都合の良いことですが、攻撃者にとっては歯がゆいことです。

しつこい攻撃者は、別の方法でネットワークを流れるフレームを盗聴しようと試みるでしょう。攻撃方法のヒントは、RFC 3756 "IPV6 Neighbor Discovery (ND) Trust Models and Threats"の中に書かれています。

この記事では、RFC 3756で述べられているいくつかの攻撃方法の中からMalicious Last Hop Routerを取り上げ、その実効性を検証します。

ページのトップ

概要

  ホストにデフォルトルーターのIPアドレスを設定するために、IPv4では手動で静的に登録するか、DHCPを用いて配信していました。もちろんIPv6でもこれらの方法によってデフォルトルーターを設定することは可能ですが、IPv6では新たな方法が提供されています。

IPv6ホストはルーターの存在を知るために、ルーター要請(Router solicit)と呼ばれるICMP6メッセージをマルチキャストアドレスでネットワークに送出します。ネットワーク内のルーターはルーター要請を受信すると、その発信元に向けてルーター広告(Router advertisement)と呼ばれるICMP6メッセージを返します。ルーター広告を受け取ったホストはその発信元アドレスをデフォルトルーターとして設定します

ルーター広告スプーフィングはこの仕組みを悪用します。攻撃者は自らルーター広告を送信して、同じサブネット内のホストを騙そうと試みます。ホストはルーター要請を送信していなくても受信したルーター広告を処理します。もし、他のホストが攻撃者のホストをデフォルトルーターとして認識すると、攻撃者はトラフィックを盗聴することができます。しかも、犠牲者のホストが攻撃者のホストをデフォルトルーターだと信じる限り、特別な細工をしなくても継続して通信内容を盗聴することができます。

しかし、ここで疑問が生じます。攻撃者がネットワークにルーター広告を送出するのは勝手ですが、ネットワークには正当なルーターが正常に稼働していて、周期的にルーター広告を送出しているはずです。他のホストに攻撃者のホストをデフォルトルーターとして選択させるにはどうすればいいのでしょうか。実は、RFC 3756はこの点についても言及しています。ですが、いきなりゴールにジャンプせずに実験を進めながら少しずつ説明します。

攻撃の詳細が判明したあと、対策について述べます。

ページのトップ

構成

詳しい説明をする前に、説明をなるべく具体的にするために用いるシステムの構成例について述べます。

                    +-------+
                    | HostA | (Ubuntu 9.04)
                    +---+---+
                        | Ether Address  : 00:11:11:aa:aa:aa
                        | IPv6 Link-Local: fe80::211:11ff:feaa:aaaa
                        | IPv6 Global    : 2001:db8:0:1:211:11ff:feaa:aaaa
                        |
               +--------+--------+
               | Ethernet Switch |
               +--------+--------+
                        |
                        | Ether Address  : 00:11:11:dd:dd:dd
                        | IPv6 Link-Local: fe80::211:11ff:fedd:dddd
                        | IPv6 prefix    : 2001:db8:0:1::/64
                   +----+----+
                   | Gateway | (FreeBSD RELEASE 8.0)
                   +----+----+
                        | Ether Address  : 00:22:22:dd:dd:dd
                        | IPv6 Link-Local: fe80::222:22ff:fedd:dddd
                        | IPv6 prefix    : 2001:db8:0:2::/64
                        |
               +--------+--------+               +-------+
               | Ethernet Switch +---------------+ HostC | (debian 5.0)
               +--------+--------+               +-------+
                        |                 Ether Address  : 00:22:22:cc:cc:cc
                        |                 IPv6 Link-Local: fe80::222:22ff:fecc:cccc
                        |                 IPv6 Global    : 2001:db8:0:2:222:22ff:fecc:cccc
                        |
                    +---+---+
                    | HostB | (Microsoft Windows Vista)
                    +-------+
             Ether Address  : 00:22:22:bb:bb:bb
             IPv6 Link-Local: fe80::1c70:b378:c333:fe15
             IPv6 Global    : 2001:db8:0:2:1c70:b378:c333:fe15
             IPv6 Temporary : 2001:db8:0:2:4a1:e849:33a9:dd90
    
                          【図 3-1】ネットワーク構成図
    

上のネットワーク構成において、HostCを操作している人物が攻撃者です。攻撃者はHostBからHostAに向けて流れるパケットを盗もうとしていると仮定します。犠牲者のホスト(HostB)と攻撃者のホスト(HostC)がいるネットワークのプレフィックスは2001:db8:0:2、もう一方のネットワークのプレフィックスは2001:db8:0:1です。2つのサブネットはGatewayでつながっています。

Gatewayでは、FreeBSDに含まれているデーモンrtadvdを実行してルーター広告を配信しています。

HostBのOSはマイクロソフト社のWindows Vistaです。WindowsではIPv6のアドレスを生成する際、EUI-64アドレスをそのまま使用せず、Message Digest-5 (MD5)を用いて元のEthernetアドレスがわからないように工夫します。このアドレスを匿名アドレス、または乱数化(randomize)されたアドレスと呼びます。さらに、有効期間の短い一時(temporary)IPv6アドレスを生成します。

WIndowsでインターフェースアドレスのランダマイズを無効にしたいときは次のコマンドを実行します。

        netsh interface ipv6 set global randomizeidentifiers=disable

そして、一時アドレスを無効にしたいときは次のコマンドを実行します。

        netsh interface ipv6 set privacy state=disable
    

既に生成されている一時アドレスはシステムを再起動したときに消えます。

この記事では、以降、一時アドレスを無効にします。

ページのトップ

実験

4.1 偽のルーター広告の送出する

  HostCが送出する偽のルーター広告の内容を以下に示します。

        Ethernet II
         + Destination: 00:22:22:bb:bb:bb
         + Source: 00:22:22:cc:cc:cc
        Internet Protocol Version6
         + Version: 6
         + Next header: ICMPv6
         + Hop Limit: 255
         + Source: fe80::222:22ff:fecccc:cccc
         + Destination: ff02::1
        Internet Control Message Protocol 6
         + Type: 134 (Router Advertisement)
         + Code: 0
         + Cur hop Limit: 64
         + Flage: 0
         + Router lifetime: 1800
         + Reachable time: 0
         + Retrans: 0
         + ICMP6 Option
           + Type: 1 (Source link-layer address)
           + Length: 8
           + Link-Layer address: 00:22:22:cc:cc:cc
         + ICMP6 Option
           + Type: 3 (Prefix information)
           + Length: 32
           + Prefix length: 64
           + Flags: 0xc0
           + valid lifetime: 2592000
           + preferred lifetime: 604800
           + prefix: 2001:0db8:0000:0001:0000:0000:0000:0000
    
                  【図 4-1】ルーター広告のデータフォーマット
    

ルーター広告には、2つのオプションを持ったICMPv6を用います。ちなみにICMP6のオプションの順番は入れ替わっても問題ありません。

Ethernetヘッダーの宛先アドレスは、正しくはIPv6マルチキャスト(33:33:00:00:00:01)であるべきです。ですが、それでは攻撃目標以外のホストに不正なルーター広告が届きます。特にネットワーク監視装置やそのエージェントには届いて欲しくありません。そのためにHostBのユニキャストアドレスを使って送信しています。

ページのトップ

4.2 攻撃の効果  Microsoft Windowsの場合

  この偽のルーター広告を攻撃対象に送ると、犠牲者のホスト(HostB)のルーティングテーブルはどのように変化するのかを観ます。以下にメッセージが届く前と後の状態を示します。

     C:\>netsh interface ipv6 show route
    
     発行     種類      Met  プレフィックス                        Idx  ゲートウェイ/インターフェイス名
     -------  --------  ---  ------------------------------------  ---  -------------------------------
     いいえ   Manual    256  ::/0                                   10  fe80::222:22ff:fedd:dddd
     いいえ   Manual    256  ::1/128                                 1  Loopback Pseudo-Interface 1
     いいえ   Manual    8    2001:db8:0:1::/64                      10  ローカル エリア接続
     いいえ   Manual    256  2001:db8:0:1:1c70:b378:c333:fe15/128   10  ローカル エリア接続
     いいえ   Manual    256  fe80::/64                              10  ローカル エリア接続
     いいえ   Manual    256  fe80::1c70:b378:c333:fe15/128          10  ローカル エリア接続
     いいえ   Manual    256  ff00::/8                                1  Loopback Pseudo-Interface 1
     いいえ   Manual    256  ff00::/8                               10  ローカル エリア接続
    
                  【図 4-2】攻撃を受ける前のHostBの経路情報
    

     C:\>netsh interface ipv6 show route
    
     発行     種類      Met  プレフィックス                        Idx  ゲートウェイ/インターフェイス名
     -------  --------  ---  ------------------------------------  ---  -------------------------------
     いいえ   Manual    256  ::/0                                   10  fe80::222:22ff:fedd:dddd
     いいえ   Manual    256  ::/0                                   10  fe80::222:22ff:fecc:cccc
     いいえ   Manual    256  ::1/128                                 1  Loopback Pseudo-Interface 1
     いいえ   Manual    8    2001:db8:0:1::/64                      10  ローカル エリア接続
     いいえ   Manual    256  2001:db8:0:1:1c70:b378:c333:fe15/128   10  ローカル エリア接続
     いいえ   Manual    256  fe80::/64                              10  ローカル エリア接続
     いいえ   Manual    256  fe80::1c70:b378:c333:fe15/128          10  ローカル エリア接続
     いいえ   Manual    256  ff00::/8                                1  Loopback Pseudo-Interface 1
     いいえ   Manual    256  ff00::/8                               10  ローカル エリア接続
    
                  【図 4-3】攻撃を受けた後のHostBの経路情報
    

ルーティングテーブルに新たなエントリーが追加されました。また、既存のルーターのエントリーも残っています。その結果、デフォルトの経路(::/0)に対するゲートウェイが2つ登録されています。

この状況で、HostBからHostAへpingを試してみたところ失敗に終わりました。

        ping -6 2001:db8:0:1:211:11ff:feaa:aaaa
    
        2001:db8:0:1:211:11ff:feaa:aaaa に ping を送信しています 2001:db8:0:2:1c70:b378:c333:fe15 から
         32 バイトのデータ:
        要求がタイムアウトしました。
        要求がタイムアウトしました。
        要求がタイムアウトしました。
        要求がタイムアウトしました。
    
        2001:db8:0:1:211:11ff:feaa:aaaa の ping 統計:
            パケット数: 送信 = 4、受信 = 0、損失 = 4 (100% の損失)、
    
                  【図 4-4】攻撃を受けた後のpingの実行結果
    

Wiresharkを使ってトラフィックを調べてみると、HostBはHostA宛のICMP6 Echo requestを包んだEthernetフレームをHostCに向けて送信していました。

ただし、実行中のプロセスには影響はないように見られます。例えば、HostBからHostAへpingを継続的に実行している最中に偽のルーター広告を送ってもpingは途切れません。

HostBから本来届くはずのないEthernetフレームが届くようになったら、そのフレームのEthernetヘッダーを変更してGatewayに向けて転送します。これで盗聴成功です。

しかし、この効果は長くは続きしません。

ページのトップ

4.3 近隣広告の不整合

 盗聴を開始してから数十秒すると、トラフィックはHostCを避けて本来流れるべき経路に戻ってしまいます。

トラフィックを観察すると、次のようなことが起きています。

  1. HostCはHostBへ偽のルーター広告を送るためにHostBのEthernetアドレスを知る必要があります。そのため、HostCはHostBへ近隣要請(Neighbor solicit)を送り、HostBから返信される近隣広告(Neighbor advertisement)を受け取ります。
  2. 一方、HostCの存在を知ったHostBは、HostCへの到達の可能性を確認するために近隣要請を送り、HostCからの近隣広告を受信します。
  3. HostCはHostBへ偽のルーター広告を送ります。そして、それを受け取ったHostBはHostCをカレントのデフォルトルーターとして認識します。
  4. その後、HostBからHostAに対してpingを実行すると、HostBはHostA宛のICMP6 Echo requestを包んだEthernetフレームをHostCに送ります。
  5. HostCは、受信したEthernetフレームのEthernetヘッダーの発信元アドレスに自分のEthernetアドレスを、そして、宛先アドレスにGatewayのEthernetアドレスを入れて再びネットに送出します。
  6. Gatewayは通常どおり動作します。受信したHostA宛のICMP6 Echo requestメッセージをHostAに転送します。そして、HostAからHostBへのICMP6 Echo replyメッセージを受け取り、それをHostB宛のEthernetフレームに包み直して転送します。
  7. GatewayがHostBにフレームを送るとき、近隣キャッシュの中でHostBの到達可能時間が残り0になっていたら、つまり時間切れになっていたら、GatewayはHostBへの到達の可能性を確かめるために近隣要請を送ります。HostBはGatewayに近隣広告を返すと同時に、HostBからGatewayに対して近隣要請を送ります。そして、GatewayがHostB宛に近隣広告を返します。
  8. 最終的にHostBは、HostCならびにGatewayと1度か2度近隣要請と近隣広告を送受信したあと、デフォルトゲートウェイをGatewayに戻して、ルーティングテーブルからHostCのエントリーを消しています。ping開始からここまでの経過時間は長くても30秒程度です。

確認した現象の中でとても気になることがあります。それはHostBのルーティングテーブルからHostCのエントリーが消えることです。もしかすると、HostCが偽のルーターだということがバレてしまったのでしょうか。そのせいで、しばらくするとデフォルトルーターがGatewayに戻るのでしょうか。

もう少し注意深く観察すると、HostCがHostBへ近隣広告を送信する際、カーネル内のipv6モジュールが生成する近隣広告に攻撃者にとって不都合な点がありました。HostCがルーターであるなら、近隣広告のFlagsにRouterビットがセットされているべきです。しかし、ルーターとしてではなくホストとして実行されているHostCのカーネルは近隣広告を生成する際、FlagsにRouterビットをセットしていませんでした。

そこで、近隣要請を受信したときに、FlagsにRouterビットをセットした近隣広告を返信するように検査用プログラムを書き換え、カーネルのIPv6を無効にした後、再度実験を行います。

実験は成功しました。HostBのルーティングテーブルに追加されたHostCのエントリーは保持され続けるようになりました。

しかし、それでも継続して盗聴することができません。

ページのトップ

4.4 デフォルトルーターを選択するポリシー

  HostCが偽のルーター広告を送信したあと、HostBは他のサブネット宛のパケットを包んだEthernetフレームをHostCに送るようになります。この動作は永続的ではなく、HostBはGatewayからのルーター広告を受け取るとデフォルトルーターをGatewayに戻してしまいます。(ルーティングテーブルにHostCのエントリーは残っています。)

Gatewayがデフォルトゲートウェイとして認識されているとき、HostBがHostA宛にpingを実行している最中にHostCからのルーター広告を受け取ってもトラフィックの流れは変わりませんでした。しかし、その逆は起こります。HostCがデフォルトゲートウェイとして認識されているとき、HostBがHostA宛にpingを実行している最中にGatewayからルーター広告を受け取るとトラフィックの流れが変わります。

RFC 2461 "Neighbor Discovery for IP Version 6 (IPv6)"によると、ホストはルーター広告を受信したとき、その発信元アドレスをデフォルトルーターリストの中に追加します。

デフォルトルーターリストに複数のエントリーがあるとき、到達可能であることが確認されているか又は到達可能と思われるルーターが、到達可能であることが不明か又はそれが疑わしいルーターより優先して選択されるべきであるとされています。

(複数の候補の中から)1つを得るとき、到達可能であることが確認されている又は到達可能と思われるルーターを返すのなら(この条件を満たすならば)、常に同じルーターを返すか、ルーターリストの中をラウンドロビン方式で巡回するかは、実装が選択しても良いとされています。

これは憶測ですが、マイクロソフトWindows Vistaの実装では、リストの中に到達可能であることが確認されているルーターが複数ある場合、その中で最も古いエントリーをデフォルトルーターに選択しているのかもしれません。

「4-1. 攻撃の効果」で、偽のルーター広告による攻撃が成功したのは、HostBの近隣キャッシュの中でデフォルトルーター(Gateway)の到達可能時間が0になっていたからです。もし、HostCからのルーター広告を受け取ったとき、その時点でGatewayが到達可能であると確認されているなら、HostBはHostCではなくGatewayをデフォルトルーターに選択します。例えば、HostBからHostAにpingを1回だけ実行し、そのあとにHostCからHostBに偽のルーター広告を送ります。そして、再びHostBからHostAにpingを実行してもトラフィックはHostCには流れません。

さて、次にやるべきことは決まりました。先に進みましょう。

ページのトップ

4.5 ルーターを無効にする

 HostBのデフォルトルーターリストの中で、HostCをGatewayより古いエントリーにするためにはどうすればいいのでしょう。Gatewayを直接攻撃してサービス停止に追い込むことはできません。そんなことをすると、横取りしたフレームを本来の宛先に転送することができません。

先にも述べましたが、RFC 3756の中にヒントがあります。攻撃者は、正当なルーターのふりをして生存時間(Router lifetime)に0を入れたルーター広告を生成し、攻撃目標のホストに送ります。このメッセージを受け取った攻撃目標のホストは、正当なルーターを無効にしてしまう可能性があります。

早速、試してみましょう。まず、HostCから偽のルーター広告を送り、次いで、Gatewayになりすまして生存時間に0を設定したルーター広告を送ります。

実験は成功しました。しかもこの攻撃は、HostBがHostAにpingを実行している最中でも、Gatewayのエントリーを無効にしてしまうことが出来ます。

攻撃を開始して、しばらく経つとGatewayから正当なルーター広告が届きます。予想では、HostCのエントリーの方が古くなるため、HostBがHostAにpingを実行している最中はトラフィックはGatewayの方に流れを変えないと考えていました。しかし、予想は外れ、トラフィックはGatewayに向かうようになります。このあと、HostCから偽のルーター広告を送るだけでは、(生存時間に0を設定したルーター広告を送らないなら、)トラフィックを横取りすることはできませんでした。どうやら、Gatewayになりすまして生存時間に0を設定したルーター広告をHostBに送っても、HostBのデフォルトルーターリストからGatewayのエントリーそのものが消える訳ではないようです。

とにかく、正当なルーターになりすまして生存時間に0を設定したルーター広告を送るという手法は有効です。この攻撃により、攻撃目標のホストに、通常使用しているデフォルトルーターが無効になったと思わせることが可能です。

ページのトップ

5 対策

  RFC 3756の"4.2.1. Malicious Last Hop Router"の中では、次のように述べられています。

(原文)
 This threat is partially mitigated in RFC 2462; in Section 5.5.3 of RFC 2462 it is required that if the advertised prefix lifetime is less than 2 hours and less than the stored lifetime, the stored lifetime is not reduced unless the packet was authenticated. However, the default router selection procedure, as defined in Section 6.3.6. of RFC 2461, does not contain such a rule.

(和訳)
 この脅威はRFC 2462で一部緩和されます。RFC 2462のセクション5.5.3では、もし、広告されたプレフィックスの生存時間が2時間より短く、かつ保持されている時間より短いなら、パケットが認証されない限り生存時間を減さないことが求められている。しかし、RFC 2461のセクション6.3.6に定義されているデフォルトルーターの選択手順は、このようなルールを含んでいない。

仮に、実装がこのような仕組みを持っていたとしても、全てのクライアントでパケット認証を機能させなくてはなりませんので、大規模なシステムでは多大な労力を必要とするかもしれません。

 別の対策として、IPv4のARPスプーフィング攻撃を高機能なL2スイッチで防ぐことが可能であるように、L2スイッチのフィルタリング機能を使ってIPv6ルーター広告スプーフィングを防ぐことが可能です。具体的には、ノードを集線しているL2スイッチにおいて正当なルーターを接続しているポートでのみルーター広告を受信可能とし、利用者のホストを接続しているポートではルーター広告を受信しないように設定します。実際、ICMP6の特定のメッセージタイプをフィルタリングできるL2スイッチはあるのですが、このようなL2スイッチは今はまだ高価で、それが複数台必要なら予算を確保するのは簡単ではないでしょう。

 すぐに実施できる有効な対策は、デフォルトルーターを手動で静的に設定し、ルーター広告を無視することです。この対策はIPv6の長所を台無しにしてしまいますが、作業が単純で、高機能なL2スイッチも必要としません。マイクロソフトWindows Vistaの場合、ネットワークプロパティでインターフェースのグローバルIPv6アドレスと共にデフォルトゲートウェイのリンクローカルIPアドレスを設定します。そのあと、netshコマンドを使ってルーター探索(Router discovery)を無効にします。netshコマンドは次のとおりです。

        netsh interface ipv6 set interface <index> routerdiscovery=disable
    

インターフェースの識別子(index)は、"netsh interface ipv6 show route"コマンドでも確認できます。例えば、[図4-2]の場合、インターフェースの識別子は10です。

ページのトップ

おわりに

  攻撃目標のホストがルーター広告を受け入れる場合、偽のルーター広告を使って目標ホストのデフォルトルーターを変更する攻撃は有効です。この攻撃は2004年5月に公示されたRFC 3756の中で言及されています。

6年前に認識されていた攻撃が今なお有効であることは少し驚きですが、前の節で述べたように対策はあります。それに、この攻撃もIPv4のARPスプーフィングやIPv6の近隣要請スプーフィングと同様、ネットワーク内の利用者がすべて信頼できる人物に限定されているなら、この脅威が顕在化する心配は無用です。

  最後に、この記事が他の正義の味方にとって少しでも役立つものになることを願っています。

ページのトップ

著作権者の文書による承諾を得ずに、本記事の一部または全部を無断で複写・複製・転載することはできません。