本記事は2022年3月9日に弊社が公開した英語ブログ“Dirty Pipe” Linux vulnerability and your containerized applications (CVE-2022-0847)を日本語化した内容です。
脆弱性“Dirty Pipe”(CVE-2022-0847)とは何か?
最近、CVE-2022-0847が作成され、Linuxカーネルの欠陥を悪用することで、任意のプロセスが権限設定や所有権に関係なくファイルを変更できるようになることが詳細に説明されました。本脆弱性は、CVE-2016-5195で報告された特権昇格の脆弱性 "Dirty COW" と類似していること、またカーネルのパイプライン実装に欠陥が存在することから、セキュリティコミュニティでは「Dirty Pipe」と命名されているそうです。この脆弱性については、Snyk Intel Vulnerability Databaseに複数のドキュメントがあるので、より詳しく知りたい場合は、そちらを参照してください。
この記事では、コンテナ化されたワークロードが直面するリスクについて説明し、コンテナイメージやその他の通常は読み取り専用のファイルの内容が、UID やファイルシステムのパーミッションに関係なく、悪意のある行為者によって変更される可能性について、その裏を探っていきます。
まず最初に、Dirty Pipeからシステムを守るために、今すぐできることを説明します。
TL;DR(要約): Linuxホストをアップグレードしましょう
この脆弱性に対する唯一の修正方法は、Linux ホストを以下のカーネルバージョンのいずれかにアップグレードすることです。
- 5.16.11
- 5.15.25
- 5.10.102
悪意のある者がお客様の環境にアクセスした場合、お客様のシステムを保護するための他の軽減策はありません。
Dirty Pipeがコンテナイメージに与える影響
CONTAINER IMAGES 101
コンテナイメージは、基本的にレイヤーを重ね合わせた集合体で構成されています。コンテナが起動すると、ランタイムエンジン(Docker、containerD、cri-Oなど)がこれらのレイヤーをマージし、その結果の集合体をファイルシステムとしてプロセスに提供します。これらのレイヤーは常に読み取り専用で、変更はコピーオンライト(COW)パターンを使用して各コンテナインスタンス用に特別に作成された読み取り/書き込みレイヤーで行われます。この読み書き層は、コンテナがシステムから削除されたときに破棄されるため、一時的なものです。また、コンテナを読み取り専用モードで起動することで、読み取り/書き込みレイヤーを省略することもでき、事実上、コンテナをイミュータブルにすることができます。
コンテナのプロセスを非特権ユーザーとして実行し、ルートファイルシステムを読み取り専用にすることは、一般的に推奨されています。このような手順を踏むと、コンテナのファイルシステムに独自のコードやスクリプトを持ち込むことが極めて困難になるため、悪意のある行為者がアプリケーションの脆弱性を利用して攻撃を拡大することが非常に難しくなります。その他のベストプラクティスについては、コンテナ・セキュリティ・ガイドを参照してください。
コンテナにおけるDirty Pipeのエクスプロイト
Dirty Pipe 脆弱性がどのように機能するかについての詳細は、この記事の範囲外です - すべての厄介な詳細については、本脆弱性を発見したオリジナルのブログを参照してください - しかし簡潔に言えば、比較的単純な一連の手順を実行することにより、ほぼすべてのファイルが、たとえそのような動作を制限するパーミッションや所有権の設定を持っていても、その内容を変更することができます。例えば、上記のリンク先の記事にあるwrite_anything
の PoC (Proof of Concept: 概念実証) コードを使用して、次の Dockerfile を使用してイメージを構築します。
次に、読み取り専用モードで実行し、write_anything
実行ファイルを使用して/etc/passwd
を変更します。
このファイルは読み取り専用で、所有者がrootであり、読み取り専用のrootファイルシステム上にあるため、このようなことはできないはずです。
次に、このコンテナを停止して削除し、新しいコンテナを起動し、新しいコンテナの/etc/passwd
を見てみましょう。
このファイルの変更は持続されました。ホストシステム上で読み取り専用である実際のイメージレイヤーのコンテンツが、以前のコンテナプロセスによって変更されたためです。この変更は、イメージが削除または置き換えられるまで、このホスト上で継続されます。
ハックを実行する前の低レベルのイメージレイヤー
ハック実行後の低レベルイメージレイヤー
実際、同じホスト上で複数のコンテナが動作している場合、このような変更は、このベースイメージ層を共有するすべてのコンテナから直ちに認識できる可能性があります(自分の r/w レイヤーで同じファイルにすでに変更を加えているものは例外です)。
3 つのコンテナで/etc/passwd
ファイルをwatch
しながら実行し、4 番目のコンテナでwrite_anywhere
ハックを実行します。
ホストにマウントされたすべてのボリュームがDirty Pipeに属しています
ご存知のように、コンテナにホストボリュームをマウントする(別名バインドマウント)のは決して良いアイデアではありません。なぜなら、単純な設定ミスにより、コンテナがホスト上のファイルを変更するための意図しないアクセス権を付与される可能性があるからです。Dirty Pipeは、ホストマウントされたボリュームが:ro
フラグを設定してマウントされていたとしても、この悪用される危険性があるため、この問題のリスクを高めています。
Dirty Pipeによる権限昇格
悪用された PoC の例の1つでは、既存の suid が設定されたバイナリを変更して通常の保護を回避することにより、欠陥を利用して昇格特権を実現します。これは、当該コンテナだけの問題ではなく、他のコンテナ内部でも使用される可能性があります。理論上では、攻撃者がアプリケーションのリモートコード実行(RCE)脆弱性を悪用し、この POC コードを注入してあなたのコンテナ内で root になれるわけです。これは、そのような動作を制限するコンテナやKubernetesの、またはその両方の設定を、実質的に回避するものです。
軽減策はあるのか?
前述したように、ホストシステムをアップグレードすることが、システムをこの脆弱性から守る唯一の方法です。このようなカーネルレベルのエクスプロイトへの対策としては、コンテナエンジンとKubernetesでの緩和策は高レベルであり、効果がありません。
ベースイメージを更新することはできないのでしょうか?
残念ながら、できません。この欠陥は、ベースイメージのファイルシステム上ではなく、実行中の全コンテナで共有されるホストのサーバーのカーネルにあるのです。これは、異なるベースイメージからなる複数のコンテナ上でuname -a
を実行することで確認できます。どれもホストのカーネルバージョンを返します。
kubernetesのSecurityContextで対策できませんか?
Kubernetes の SecurityContext の設定であるreadonlyRootFilesystem:true
、runAsNonRoot:true
、runAsUser:
、AllowPrivilegeEscalation:false
は、どのユーザーもこの脆弱性を利用してこれらの設定をバイパスできるため、すべて無効となります。
これらの設定を使用すべきではないと言っているのではありません。その正反対で、これらの設定は多層防護を実践する優れた例であり、他の多くの種類の攻撃からクラスタを保護することができます。
実際、私たちはKubernetesセキュリティチートシート*で、SecurityContext
設定と、Kubernetesアプリケーションのデプロイメントを強固にするためにこの設定を使用すべき理由について説明しています。また、Snykの無料のIaCスキャンツールを使ってKubernetesマニフェストをスキャンすれば、これらのような設定ミスを発見して修正することができます。以下のリンクをクリックして、今日から使い始めてください。
(* 訳者注記)Kubernetesセキュリティチートシートは、現在、日本語化を進めています。日本語版は@SnykSecにて公開いたします。
まとめ
まだの方は、すぐにホストをアップデートしてください。また、上記のトピックに興味を持たれた方は、以下のリンクでより詳細をご確認ください。
- CM4Allのブログ:Dirty Pipe 脆弱性の発見に関する記事
- Snykのブログ:イメージ構築、レイヤー、コンテナ脆弱性スキャンの詳細を掘り下げる
- Snykのチートシート:理解しておくべき10のKubernetes Security Context設定
- ArsTechnica:Linuxはここ数年で最も深刻度の高い脆弱性に噛まれている