イエラエ CSIRT支援室 第 32 回 L2TP/IPSecトンネルの崩壊と戦った話 | ScanNetSecurity
2024.04.25(木)

イエラエ CSIRT支援室 第 32 回 L2TP/IPSecトンネルの崩壊と戦った話

L2TP/IPSec VPN を設定する機会があり、その際に「トンネル内でサイズが大きなパケットを 1 つでも送出した瞬間にトンネル全体の通信が止まって VPN接続が切れる」というトンネル崩壊現象に悩まされました。

製品・サービス・業界動向 業界動向

●はじめに

 イエラエセキュリティの中の人一号です。先日、L2TP/IPSec VPN を設定する機会があり、その際に「トンネル内でサイズが大きなパケットを 1 つでも送出した瞬間にトンネル全体の通信が止まって VPN接続が切れる」というトンネル崩壊現象に悩まされました。

 調査の結果、やや珍しいと思われる原因が判明し対策方法も分かったので、備忘録的に記しておきます。

●環境

[SEIL/X1 Ver. 5.94 (Client)] <=(L2TP/IPSec)=> [xl2tpd with kernel support (Server)]

●現象

 SEIL/X1 が張ったトンネル内で、pppインターフェースの MTU より大きいパケットをクライアント側から一つでも送出した瞬間にトンネル内の全通信が止まり接続が切れる。

 ただし、Windows 10 に組み込まれている L2TP/IPSecクライアントが同一環境・同一設定で張ったトンネルでは、通信切断は起きない。

●原因

 SEIL/X1 は、L2TP のレイヤーで、Data Packet に対して Sequence Number を付与します。Sequence Number は、L2TP/IPSecパケット 1 つ毎に 1 インクリメントされます。

 Data Packet に対する Sequence Number はoptional(https://tools.ietf.org/html/rfc2661#page-44)であり、SEIL/X1 は Sequence Number を付与します。 Sequence Number が付与されている場合、サーバーは Sequence Number を参照しながら L2TP/IPSecパケットを処理します。

 トンネル内で送出されるパケットが MTU より大きい場合にはパケットは分割され、それぞれのパケットが別々の L2TP/IPSecパケットに包まれて対向側に向けて送出されます。

 分割されるパケットには、それぞれ別の Sequence Number が振られます。 分割されるパケットの直前の Sequence Number が n – 1 で分割数が 2 とすると、分割されるパケットに振られる Sequence Number は n と n + 1 になります。

 L2TP/IPSec のパケットは UDP で届けられるため、経路上で順番が入れ替わる可能性があります。

 末端の SEIL/X1 は順番通りにパケットを送出するようですが、私が VPN を設定していた経路では(どこで入れ替わっているかは不明ですが)サーバーに到達するまでに分割されたパケットの順番が入れ替わります (1)。

 つまり、サーバーから見ると Sequence Number が 1 飛んだ n + 1 のパケットが先に到着します。

 サーバーはデフォルトでは Sequence Number が飛んだ場合に対応しておらず、Sequence Number が 1 ずつインクリメントされることを期待しているので、Sequence Number が飛んだ瞬間に状態が壊れて以後のパケットを受け付けなくなります。 Windows 10 の場合も同様にパケット順序の入れ替わりが起こりますが、そもそも Sequence Number が付与れていない (2) ようで、サーバーは入れ替わりに気付かずに処理を続けます。

●現象発生時のパケットとログ

 pppインターフェースの MTU が 1400 の設定で、通信が全てトンネル内を通過するようにしたクライアント側の Linux から、次のコマンドを実行してパケットとデバッグログを記録しました。この設定ではペイロード長が 1373 以上になるとパケットが分割されます。

ping -s 1372 (疎通確認先の IPアドレス) (Ctrl+C で打ち切り)
ping -s 1373 (疎通確認先の IPアドレス)

 L2TP/IPSec のパケットをサーバー側でキャプチャして Wireshark で復号し L2TPヘッダの内容を表示したものを、時系列で次に示します。Ns が Sequence Number を指していて、30、32、31と順番が飛んでいることが分かります。

———
現象発生直前の ICMP Requestパケットの L2TPヘッダ

Layer 2 Tunneling Protocol
  Packet Type: Data  Message Tunnel Id=25085 Session Id=42025
    0... .... .... .... = Type: Data Message (0)
    .1.. .... .... .... = Length Bit: Length field is present
    .... 1... .... .... = Sequence Bit: Ns and Nr fields are present
    .... ..0. .... .... = Offset bit: Offset size field is not present
    .... ...0 .... .... = Priority: No priority
    .... .... .... 0010 = Version: 2
  Length: 1416
  Tunnel ID: 25085
  Session ID: 42025
  Ns: 30
  Nr: 65535
———
分割された ICMP Requestパケットの L2TPヘッダ (先に到達した方)

Layer 2 Tunneling Protocol
  Packet Type: Data  Message Tunnel Id=25085 Session Id=42025
    0... .... .... .... = Type: Data Message (0)
    .1.. .... .... .... = Length Bit: Length field is present
    .... 1... .... .... = Sequence Bit: Ns and Nr fields are present
    .... ..0. .... .... = Offset bit: Offset size field is not present
    .... ...0 .... .... = Priority: No priority
    .... .... .... 0010 = Version: 2
  Length: 41
  Tunnel ID: 25085
  Session ID: 42025
  Ns: 32
  Nr: 65535
———
分割された ICMP Requestパケットの L2TPヘッダ (後に到達した方)

Layer 2 Tunneling Protocol
  Packet Type: Data  Message Tunnel Id=25085 Session Id=42025
    0... .... .... .... = Type: Data Message (0)
    .1.. .... .... .... = Length Bit: Length field is present
    .... 1... .... .... = Sequence Bit: Ns and Nr fields are present
    .... ..0. .... .... = Offset bit: Offset size field is not present
    .... ...0 .... .... = Priority: No priority
    .... .... .... 0010 = Version: 2
  Length: 1412
  Tunnel ID: 25085
  Session ID: 42025
  Ns: 31
  Nr: 65535
———

 サーバー上で採集した l2tp_coreモジュールのデバッグログを次に示します。 パケットが入れ替わって状態が壊れた結果、サーバーは既に到達した ns=32 のパケットを待ち続ける状態になっています。

[68489.340002] l2tp_core: sess 25085/42025: recv data ns=30, nr=65535, session nr=30

[68489.340039] l2tp_core: sess 25085/42025: updated nr to 31

[68491.247541] l2tp_core: sess 25085/42025: recv data ns=32, nr=65535, session nr=31

[68491.247575] l2tp_core: sess 25085/42025: oos pkt 32 len 41 discarded, waiting for 31, reorder_q_len=0

[68491.249427] l2tp_core: sess 25085/42025: recv data ns=31, nr=65535, session nr=31

[68491.249454] l2tp_core: sess 25085/42025: updated nr to 32

[68492.252559] l2tp_core: sess 25085/42025: recv data ns=34, nr=65535, session nr=32

[68492.252594] l2tp_core: sess 25085/42025: oos pkt 34 len 41 discarded, waiting for 32, reorder_q_len=0

●対策

 サーバー側で、pppd を介してカーネルの l2tp_coreモジュールに Sequence Number が飛んだパケットを並べ替えるよう伝えるオプションを渡し、適宜並べ替えてもらうようにします。

 具体的には、xl2tpd が利用する pppd のオプションファイルに次の行を加えます。

pppol2tp_reorderto 30

 このオプションは L2TP Data Packet の並び替えタイムアウトを指定するもので、デフォルトでは 0 です。

https://github.com/paulusmack/ppp/blob/ppp-2.4.7/pppd/plugins/pppol2tp/pppol2tp.c#L100

 このオプションが指定されると、L2TPパケットを処理する l2tp_coreモジュールが飛んだパケットを並べ替えてくれるようになります。

https://github.com/torvalds/linux/blob/v4.17/net/l2tp/l2tp_core.c#L512

●Sequence Number の付与

 RFC2661 には「LAC(クライアント)が Sequence Number を Data Channel で使いたい場合には Sequencing Required AVP をセットアップ中に送出することで要求でき (3)、その AVP が無ければ付与の有無は LNS(サーバー)が制御して LAC はそれに従う(4)」(意訳)というようなことが書かれています。

 今回キャプチャしたパケットや採集したログを見る限り、クライアントがSequencing Required AVP を送出している箇所は見つからず (5)、サーバーが Sequence Number 無しの Data Packet を送ってきてもそのまま Sequence Number を付与し続けている (6) ので、SEIL/X1 の L2TP/IPSecクライアントは無条件で Sequence Number を付与する実装になっている可能性があります。

●謝辞

 この記事の執筆にあたっては株式会社レピダムの名古屋さんにご協力を頂きました。この場で感謝申し上げます。

1. 実験の結果「サイズが一定の関係にある大きい UDPパケットと小さい UDPパケットが十分小さい間隔で送出された場合、大きい方が先に送出されていても小さい方が先に届く」という現象を確認しました。MTU を超えて分割されたパケットがちょうどこの現象に当たるようです。

2. 手元の環境でキャプチャしたパケットでは付与されていないことを確認しました。

3. “The LAC may request that sequence numbers be present in data messages via the Sequencing Required AVP (see Section 4.4.6).”

4. “If this AVP is not present, sequencing presence is under control of the LNS.” “Thus, if the LAC receives a data message without sequence numbers present, it MUST stop sending sequence numbers in future data messages.”

5. トンネル確立開始時からキャプチャした L2TP/IPsecパケットに Wireshark上でフィルタ

l2tp.avp.type == 39

を適用しても該当するパケットが無く、サーバー側で xl2tpdに

debug avp = yes

を設定した状態でログを確認しても当該AVP を受信している様子がありませんでした。

6. トンネル確立開始時からキャプチャした L2TP/IPsecパケットに Wireshark上でフィルタ

(l2tp.seq_bit == 1) && (l2tp.type == 0) && (ip.src == <クライアントのIP>)

とするとパケットが複数該当し、

(l2tp.seq_bit == 1) && (l2tp.type == 0) && (ip.src == <サーバーのIP>)
とすると該当するパケットはありませんでした。

プラットフォーム診断をご希望の方はこちらから

《GMOサイバーセキュリティ byイエラエ株式会社》

関連記事

特集

PageTop

アクセスランキング

  1. 訃報:セキュリティの草分けロス・アンダーソン氏 死去 67 歳、何回分かの生涯に匹敵する業績

    訃報:セキュリティの草分けロス・アンダーソン氏 死去 67 歳、何回分かの生涯に匹敵する業績

  2. 社員のセキュリティ意欲高める施策とは? 罰則は逆効果 ~ プルーフポイント「2024 State of the Phish」日本語版公表

    社員のセキュリティ意欲高める施策とは? 罰則は逆効果 ~ プルーフポイント「2024 State of the Phish」日本語版公表

  3. LINEヤフー委託先への不正アクセス、報告書を受け 2 度目の行政指導

    LINEヤフー委託先への不正アクセス、報告書を受け 2 度目の行政指導

  4. 今日もどこかで情報漏えい 第23回「2024年3月の情報漏えい」なめるなという決意 ここまでやるという矜恃

    今日もどこかで情報漏えい 第23回「2024年3月の情報漏えい」なめるなという決意 ここまでやるという矜恃

  5. スペシャリスト集結! マネーフォワード・ラック・富士ソフト・電通総研から学ぶ、脆弱性診断内製化の成功法則とは? AeyeScan 導入企業との公開対談

    スペシャリスト集結! マネーフォワード・ラック・富士ソフト・電通総研から学ぶ、脆弱性診断内製化の成功法則とは? AeyeScan 導入企業との公開対談PR

  6. タカラベルモントの海外向けウェブサイトのサーバがフィッシングメール送信の踏み台に

    タカラベルモントの海外向けウェブサイトのサーバがフィッシングメール送信の踏み台に

  7. 情報処理学会、高等学校情報科の全教科書の用語リスト公開

    情報処理学会、高等学校情報科の全教科書の用語リスト公開

  8. Acompany で 4 件の Google フォーム誤設定、最大 164 名の個人情報が閲覧可能に

    Acompany で 4 件の Google フォーム誤設定、最大 164 名の個人情報が閲覧可能に

  9. 国内カード発行会社のドメイン毎の DMARC 設定率 36.2%「キャッシュレスセキュリティレポート(2023年10-12月版)」公表

    国内カード発行会社のドメイン毎の DMARC 設定率 36.2%「キャッシュレスセキュリティレポート(2023年10-12月版)」公表

  10. LINE client for iOS にサーバ証明書の検証不備の脆弱性

    LINE client for iOS にサーバ証明書の検証不備の脆弱性

ランキングをもっと見る