TensorFlowだけじゃない!安全でないデシリアライゼーション in Python
Google によって開発されていた TensorFlow に任意のコード実行に繋がる脆弱性(CVE-2021-37678)が報告されました。
この脆弱性は安全でないデシリアライゼーションと呼ばれる脆弱性で、多くのプログミング言語に存在するバイト列等の表現で直列化されたデータを元のオブジェクトに変換する処理で発生する脆弱性です。
報告されたものは TensorFlow の脆弱性ですが、TensorFlow と同様の実装がされているソフトウェアにも影響があり、GitHub で検索をしただけでも多くプロジェクトで同様の実装が見られます。
今回は、TensorFlow の脆弱性を例に、Python の PyYAML における安全でないデシリアライゼーションについて解説します。
また、この記事を書くための調査の中で、新たな脆弱性を発見し、CVE-2021-43811(Amazon Translate でも利用されている機械翻訳フレームワーク Sockeye の脆弱性)と CVE-2021-41078(Python のマイクロサービスフレームワーク nameko の脆弱性)を取得しました。
「安全でないデシリアライゼーション」概要
安全でないデシリアライゼーション(Insecure Deserialization)とは、多くのプログミング言語に存在するバイト列等の表現で直列化されたデータを元のオブジェクトに変換する処理で発生する脆弱性です。
攻撃者がこの脆弱性を悪用することにより、DoS や状態の改ざん、最悪の場合は任意のコード実行を引き起こす可能性があります。
2021 年のOWASP Top 10でも 8 番目に含まれているものになっています。
「シリアライゼーション」は、アプリケーション内のメモリ上のオブジェクトなどをバイト列や JSON、YAML 等の形式に変換する処理を示します。
「デシリアライゼーション」は、シリアライゼーションによってオブジェクトをバイト列などの表現に変換したデータをアプリケーションで取り扱うことができるようにオブジェクトに再構築する処理を示します。
以下の記事で、Java における安全でないデシリアライゼーションを解説していますのでこちらの解説も参考になります。
今回は、最近公開された TensorFlow の任意のコード実行にも繋がる恐れのある脆弱性(CVE-2021-37678)を例に Python の PyYAML における安全でないデシリアライゼーションについて解説していきたいと思います。
TensorFlow の安全でないデシリアライゼーションの脆弱性
2021 年 8 月 12 日、TensorFlow に任意のコード実行に繋がる脆弱性(CVE-2021-37678)が公開されました。
この脆弱性は、YAML フォーマットから Keras モデルへとデシリアライズする時に任意のコードが実行されるというものです。
TensorFlow のセキュリティアドバイザリには以下の脆弱性を再現することが可能なコード(PoC)も提示されています。
このコードを実行すると、os.system('cat /etc/passwd')が実行され、/etc/passwdファイルの中身が表示されます。
payload に書かれているものがmodels.model_from_yamlで読み込まれると、内部では PyYAML のyaml.unsafe_loadが呼び出されています。
unsafe_load は名称からわかるように信頼できないデータを読み込むことで簡単に悪用されてしまうものであり、公式のWikiでも注意書きされています。
このように、今回の CVE-2021-37678 の脆弱性は TensorFlow の脆弱性ではありますが、PyYAML のyaml.unsafe_loadを利用しているソフトウェアであれば同様の影響を受ける恐れのあるものだとわかります。
また、この TensorFlow の脆弱性に対する修正方法として、修正が困難だったため YAML 形式の対応を辞める、という対応が行われました。
GitHub で yaml.unsafe_load を検索すると・・・
PyYAML のyaml.unsafe_loadを利用していると先ほど説明した TensorFlow の脆弱性と同様の影響が受ける恐れがあることがわかりました。
unsafe_load という名称からわかるように、明らかに安全ではないものはあまり使われることはなく、TensorFlow のようなケースは滅多にないように思われるかもしれません。
しかし、GitHub で yaml.unsafe_load を検索してみますと、Python の言語だけで絞ると執筆時点では 644 コード見つけることができました。
また、unsafe_load を直接利用するのではなく、load を利用する時に Loader として UnsafeLoader を呼ぶケース(Loader=yaml.UnsafeLoader)も考えられます。
その場合も検索してみますと、484 コード見つけることができました。
傾向として、TensorFlow のような機械学習に関連する OSS で YAML 形式の config ファイルを UnsafeLoader で読み込むものが多いように思われます。
また、コード内で UnsafeLoader を使うことのリスクを表示しているものや、以前まで load を使っていたがアップデートで利用できなくなってしまったため、UnsafeLoader に切り替えた、というものもあります。
信頼できない config ファイルを読み込む、というユースケースはほぼないとは思われますが、OSS の開発側はリスクを認識していても利用者側が悪意のあるファイルを読み込むとこのような脆弱性の影響を受ける、ということを認識していない場合もありますので注意が必要です。
調査の中で新たな脆弱性を発見
上記の方法での GitHub の検索結果の中には、世の中で広く使われているようなものはあまり多くないように思われましたが、2 つほど気になるプロジェクトがあったため調査を行いました。
調査の中で、Amazon Web Services Labs が管理し、Amazon Translate などの機械翻訳に利用されている Sockeye と Python のマイクロサービスフレームワークの nameko にも影響があることがわかりました。
TensorFlow と同様に YAML 形式の config ファイルを読み込む時に任意のコード実行に繋がる脆弱性を発見し、メンテナーに脆弱性を再現するための PoC と共に報告を行いました。
その結果、修正が行われ、 CVE-2021-43811 (awslabs/sockeye)と CVE-2021-41078 (nameko/nameko)として公開されました。
yamory としては初の CVE の取得となりました。
脆弱性の発見から調査、報告、CVE の取得までの詳細に関しては別途記事を書きたいと思います。
load()を使う場合も注意が必要
unsafe_load は安全ではないことがわかりましたが、デフォルトの load を使えば大丈夫なのでしょうか?
公式の Wiki を確認してみると、「PyYAML yaml.load(input) Deprecation」と書かれています。
これはバージョン 5.1 以前では、以下のように load()を利用していても任意のコード実行に繋がってしまう脆弱性(CVE-2017-18342)があったためです。
その後も脆弱性(CVE-2020-1747)が発見され、修正されましたが、再度パイパスできる脆弱性(CVE-2020-14343)が発見されたため、現状のデフォルトの load(FullLoader)は今後なくなる可能性があり、非推奨となっています。
そのため、バージョン 5.4 以前の PyYAML を利用している場合には、デフォルトの load を使っている場合にも脆弱性を受ける恐れがあります。
間接的に PyYAML を使う場合にも影響
PyYAML で unsafe_load やデフォルトの load()を使う場合には注意が必要だと解説しました。
また、TensorFlow でも内部で PyYAML の unsafe_load が使われていたために脆弱性が報告された例も紹介しました。
自分たちは(直接)PyYAML を利用していないから大丈夫と思わずに、間接的に PyYAML を使っていないかも把握することが大切です。
GitHub で yaml.load を検索してみますと、174,250 コード見つけることができます。
すべてのコードが脆弱であるということではありませんが、2021 年 1 月 20 日に公開された 5.4 以前のバージョンを使っている場合にはリスクがあります。
OSS の中には、開発者が PyYAML の脆弱性を把握できておらず、アップデートできていない場合やそもそもメンテナンスがされていないものも存在します。
自分たちが間接的に利用しているライブラリとそのバージョンの把握まで行うことは大変ではありますが、このような推移的(間接)依存のライブラリによる脆弱性の影響も無視することはできません。
おわりに
今回は、TensorFlow の脆弱性(CVE-2021-37678)の解説から、TensorFlow 以外でも PyYAML を利用している場合には影響があることを説明しました。
また、調査の中で新たに TensorFlow と同様の任意のコード実行に繋がる脆弱性を発見・報告し、CVE-2021-43811(awslabs/sockeye)と CVE-2021-41078(nameko/nameko)の脆弱性として公開されました。
(報告した脆弱性が修正され、公開されるまでこの記事の公開を止めていたため、4 ヶ月ほど前の少し古い話題の tensorflow の脆弱性の記事となってしまいました。)
PyYAML を利用する場合には、最新のバージョンを採用し、safe_load を利用することをおすすめします。
また、直接 PyYAML を利用していない場合でも、利用しているソフトウェアに PyYAML が組み込まれているときには影響を受けることがあります。
自分たちが利用しているソフトウェアに関しては、直接利用しているものだけでなく、間接的に利用しているもの含めて把握することが大切です。
yamory では、利用しているアプリケーションライブラリのソフトウェアの一覧を取得し、その中に含まれる脆弱性の把握・管理を行うことができるサービスです。
アプリケーションライブラリの脆弱性だけでなく、GPL、MIT ライセンスなどのライセンス情報の把握も行うことができます。
また、これまではアプリケーションライブラリのみに対応していましたが、サーバのミドルウェア・OS のソフトウェア・脆弱性管理も行うことができるようになりました。
無料でトライアルもできますので、ぜひ一度お問い合わせください。
エンジニア・セキュリティエンジニアを募集しております。こちらより応募お待ちしております。
参考文献
- Arbitrary code execution due to YAML deserialization · Advisory · tensorflow/tensorflow
- uiuctf 2020 - HackMD
- Google's TensorFlow drops YAML support due to code execution flaw