Go と Rust の “net” library に影響する IP アドレス解釈の脆弱性とは?

Go, Rust “net” library affected by critical IP address validation vulnerability

2021/08/07 BleepingComputer — Go や Rust などの言語で使われている “net” library も、混合形式 (mixed-format) の IP アドレス検証の脆弱性の影響を受けている。このバグは、IP アドレスが 8進数と 10進数の混合形式で提供されている場合でも、net library が 10進数として処理することに関係している。その結果として、net に依存するアプリケーションは、サーバー・サイド・リクエスト・フォージェリ (SSRF) およびリモート・ファイル・インクルージョン (RFI) の脆弱性にさらされる可能性がある。この欠陥は、何千ものアプリケーションで使用されている、netmask library の実装にも影響を与えていた。その後に、Python の標準ライブラリである、ipaddress にも脆弱性があることが判明した。

ゼロを先頭にすると IP アドレスが変わる

今週の DEF CON において、セキュリティ研究者である Cheng Xu / Victor Viale / Sick Codes / Nick Sahler / Kelly Kaoudis / opennota / John Jackson が、Go および Rust の net モジュールに欠陥があることを公表した。この脆弱性は、CVE-2021-29922 (Rust) および CVE-2021-29923 (Golang) として追跡されており、net における混合形式 IP アドレスの処理に、より具体的に言うと、10進数の IPv4 アドレスの先頭にゼロが含まれつときの処理に関係している。GitHub で “import net ” を検索すると、net library を使用している Go だけでも、400万以上のファイルが見つかる。

IP アドレスは、16進数や整数などの、さまざまな形式で表すことができるが、一般的に目にする IPv4 アドレスは 10進数形式で表される。例として、BleepingComputer の IPv4 アドレスは、10進数で表すと 104.20.59.209 だが、8進数だと 0150.0024.0073.0321 になる。たとえば、10進法で 127.0.0.1 という IP アドレスが与えられたとする。これは、ローカル・ループバック・アドレスまたは localhost として広く理解されている。このアドレスの前にゼロを付けた場合、アプリケーションは 0127.0.0.1 を 127.0.0.1 または、他の何かとして解析するのだろうか?

Web ブラウザで試してほしい。BleepingComputer によるテストでは、Chrome のアドレスバーに 0127.0.0.1 と入力すると、8進数形式の IP として扱われる。Enter または Return を押すと、IP は 10進数の 87.0.0.1 に変わるが、ほとんどのアプリケーションは、このような曖昧な IP アドレスを扱うことになっている。特に、127.0.0.1 はパブリック IP アドレスではなくループ・バック・アドレスであり、その曖昧な表現によりパブリック IP アドレスに変更され、全く別のホストにつながってしまうという可能性もある。しかし、net library の場合は、先頭のゼロは取り除かれ、捨てられてしまう。

IETF のドラフト (正式な仕様になる前に期限切れ) によると、IPv4 アドレスの一部は、先頭に「0」が付くと 8進数として解釈される。このように、混合形式の IPv4 アドレスの解析に関するルールは、アプリケーションごとに異なる。たとえば、Go と Rust の net モジュールは、研究者のレポート [12] にあるように、IPv4 アドレスの 8進数を 10進数とみなす。そのため、開発者が net を使用して IP アドレスが特定の範囲に属しているかどうかを検証する場合 (ACL に対する IP リスト解析など)、IPv4 アドレスの 8進数ベースの表現では、結果が間違っている可能性がある。これにより、アプリケーションに Server-Side Request Forgery (SSRF) や Remote File Inclusion (RFI) の脆弱性が発生することがある。

複数のアプリケーションと言語に影響

このバグの影響を受ける言語は、Go と Rust だけではない。この混合形式 IP アドレス検証バグは、以前にも Python の ipaddress ライブラリ (CVE-2021-29921) や、netmask の実装 (CVE-2021-28918 CVE-2021-29418) などの、類似のライブラリに影響を与えていた。プロジェクトのメンテナによると、Golang の net モジュールには、ベータ・バージョン 1.17 でパッチが発行される予定だ。Sick Codes は BleepingComputer のメールインタビューに対して「Go の脆弱性は、CIDR ブロックを扱うだけなので、rust よりも若干影響が少ない。しかし、Kubernetes が修正パッチを cherry-pick チするほどの重要性があった。全体として、それらはその言語で書かれた全てのプロジェクト自体に、影響を与える標準ライブラリの変更である、多くのテストが必要であり、また、パッチが冗長になった」と答えている。BleepingComputer が確認したところによると、Rust については、すでに修正プログラムが net ライブラリにマージされているとのことだ。Rust 言語のユーザーは、この脆弱性に対する緩和策を取り込んだ、バージョン 1.53.0 以上を使用する必要がある。

8進数と10進数の問題は、いろんなところに有るのだろうと思ってしまう記事ですね。どちらにも、存在意義が有るのですから、顔を立ててあげなければなりません。というわけで、研究者たちが問題を解析して、それをベンダーが直すというエコシステムが機能するわけですが、とても有り難いことだと、つくづく思ってしまいます。

%d bloggers like this: