This post is also available in: English (英語)

概要

本稿では、コンテナー エスケープ技術を確認し、それらの影響を評価し、エンドポイント検出・対応 (EDR) の観点からエスケープを検出する方法を明らかにします。

クラウド サービスの人気とともに、コンテナー利用数も増加しており、コンテナーはいまやクラウド インフラに組み込まれた部品の 1 つとなりました。多くの利点をもつコンテナーですが、それでも攻撃技術の影響は受けます。そうした攻撃技術の 1 つがコンテナー エスケープ (container escape: コンテナーからの脱出) です。

多くのコンテナーはインターネットに接続されていることから、セキュリティ リスクはいっそう高まります。たとえばコンテナーへの低い権限のアクセスを取得した外部攻撃者は、構成ミスや脆弱性の悪用などさまざまな方法で、そのコンテナーからの脱出を試みることでしょう。

コンテナー エスケープは組織にとって重大なセキュリティ リスクです。なぜならこれが攻撃チェーンにおける要石となって、悪意のある脅威アクターにアクセスを許すことになりかねないからです。私たちは以前、そのような攻撃チェーンを runC の脆弱性に関する記事のなかで発表しました。その記事では、攻撃者がどのように CVE-2019-5736 を悪用し、root レベルのコード実行を取得し、Docker コンテナーから脱出しうるのか、その技術を論じました。その記事の発表以降もさまざまな組織が同様の脆弱性を多数公表していますし、それらの脆弱性は攻撃者によるコンテナー脱出に利用される可能性があります。

パロアルトネットワークスのお客様は、本稿で紹介するコンテナー エスケープの技術から、CortexPrisma Cloud の両ソリューションを通じてさらに適切に保護されています。

侵害の懸念があり弊社にインシデントレスポンスに関するご相談をなさりたい場合は、こちらの問い合わせフォームからご連絡いただくか、infojapan@paloaltonetworks.com まで電子メールにてお問い合わせください (ご相談は弊社製品のお客さまには限定されません)。

関連する Unit 42 のトピック Container Escape, Containers, Docker, Kubernetes

コンテナーとは

最も単純な形式の場合、コンテナーとは要するにアプリケーションを構成するプロセスのグループです。これらのグループは隔離されたユーザー空間で実行されていますが、同じカーネル空間を共有しています。これは、ホスト全体が仮想化される仮想マシンとは対照的です。コンテナーのしくみを見ていく前に「隔離されたユーザー空間」が何を意味するのかを説明しておきます。

なかには、コンテナーが実際には隔離されたユーザー空間ではなく仮想化を使っているケースがあります。そうしたケースは本稿には当てはまりません。

なぜコンテナーが必要なのか

コンテナーはリソースの効率利用のために使われています。コンテナーを使えば、1 台のサーバー上で複数のシステムを使えるようになります。オペレーティング システムは「名前空間 (namespace)」というメカニズムを提供しています。コンテナーはこの名前空間を使って隔離されたプロセス ツリーやネットワーク スタック、ファイル システム、そのほかさまざまなユーザー空間のコンポーネントを作成します。これによってリソースの効率利用が実現されています。

コンテナー内での隔離とは、各アプリケーションが自分専用にカスタマイズされた環境を持てることを意味します。同時に実行できない複数のアプリケーションがある場合は、同一サーバー上のそれぞれに専用のコンテナー内で動作させればよいことになります。

このアプローチのおかげで、コンテナーはホストから抽象化された独自のユーザー空間のコンポーネント群と対話できます。つまり、コンテナーごとに隔離されたユーザー空間が作られることになります。したがって、あるコンテナー内のアプリケーション群は、それぞれが専用サーバー内で実行されているかのように動作することができます。この特徴が、コンテナーがマイクロサービス ベースのアプリケーションに最適である理由でもあります。

コンテナーには高い移植性もあります。動作に必要なすべての依存関係を保持しているので、サポートされたコンテナー ランタイムを実行している任意のシステム上で、シームレスに実行できます。

とはいえ、こうしたコンテナーの状況は課題ももたらします。コンテナーは同じカーネルを共有しており、ホストのユーザーモードから完全には隔離されていないケースが多くなっています。したがって、コンテナー環境の制約を逃れようとする攻撃者が使う、さまざまな技術からの影響を受けやすくなっているのです。これらの技術は総称して「コンテナー エスケープ」と呼ばれます。

コンテナーはどのように機能するのか

コンテナー内部のしくみを詳しく解説する前に、Linux オペレーティング システムの動作について理解しておく必要があります。Linux では、プロセスが生成されると、そのプロセスは親プロセスから属性 (attribute) を継承します。それには次のものが含まれます。

  • 権限
  • 環境変数 (明示的に定義されていない場合)
  • ケイパビリティ
  • 名前空間

コンテナーはこのメカニズムを利用して隔離されたプロセス ツリーを生成します。

コンテナー オーケストレーションを担当するアプリケーションは、コンテナー ランタイムと呼ばれます。

コンテナー ランタイムはプロセス開始とその属性の調整という役割を担っていて、対象プロセス自体に加えてその子プロセスすべての制限や隔離を行っています。その後、対象プロセスは「init」に名前が変更され、コンテナー構成ファイルで定義されたコマンドを実行します。

通常はコンテナー ランタイムが直接使われることはなく、コンテナー CLI やコンテナー ランタイムと通信するコンテナー オーケストレーション システムなどのアプリケーションを通じて使われます。

コンテナー CLI の例としては、Docker Engine があげられます。Docker Engine は containerd をコンテナー ランタイムとして使い、Dockerfile をコンテナー構成ファイルとして使います。ほかによく利用されているコンテナー オーケストレーション システムとしては Kubernetes があります。こちらもコンテナー ランタイムとして containerd を使えます。

プロセスの隔離あたってコンテナー ランタイムが変更する属性としては次のものがあげられます。

すべてのコンテナー エンジンがこれら各属性を活用しているわけではありませんが、多くのエンジンで活用されています。

コンテナーのしくみをもっとよく理解するため、コンテナーの隔離と権限の制限にとくに関連の深い 2 つの属性、ケイパビリティと名前空間の例を調べてみましょう。

ケイパビリティ

ケイパビリティについて、Linux の man ページ は以下のように述べています。

Linux では、従来スーパーユーザーに関連付けられていた権限を、独立して有効化・無効化のできる、『ケイパビリティ』と呼ばれる個別の単位に分割しています。

本質的に、ケイパビリティ属性というのは、その名前の意味する「プロセスが実行可能 (capable) なアクションの範囲」そのものです。

Linux がケイパビリティ属性を実装した理由は、単純なユーザーやグループだけでなく、もっと多くの手段でプロセスを制限する必要があるためです。ケイパビリティ属性は、とくに root 権限を持つプロセスが実行できる操作を制限します。

以下の図 1 は、Linux のケイパビリティの包括的なリストです。

この画像は、ターミナルの黒い背景に白い等幅フォントで示した Linux のケイパビリティ名の一覧です。システム レベルのセキュリティを構成するための「cap_chown」や、「cap_kill」、「cap_setuid」などのさまざまなシステム パーミッション (権限) が表示されています。
図 1. 利用可能な Linux のケイパビリティのリスト

図 1 に示したように、chown (cap_chown) や ptrace (cap_sys_ptrace) などのよく使われる操作ですら、ケイパビリティ メカニズムで制御可能な root 操作の一覧に含まれています。詳細についてはケイパビリティに関する Linux の man ページを参照してください。

このロジックは単純です。ケイパビリティを削除すると、たとえ root 権限があっても対応する操作は実行できなくなります。たとえば、cap_sys_ptrace ケイパビリティを削除した場合、プログラムを起動したユーザーの権限レベルに関係なく、プロセスはほかのプロセスに対して ptrace システム コール (syscall) を実行できなくなります。

コンテナー作成にかかわるプロセスから不要な高権限のケイパビリティを戦略的に削除することで、コンテナー エンジンは root 権限でもコンテナーを安全に実行できるようになります。このセキュリティ メカニズムは、Linux の継承可能なケイパビリティ メカニズムによって可能となっています。

ただし残念ながら、コンテナー エンジンを使ってコンテナーを立てるさい、管理者が高権限のケイパビリティを全部は削除していないかもしれません。そうした場合には、コンテナー内からプロセスが利用できる特定のケイパビリティに基づいて、攻撃者らはそれら残されたケイパビリティをさまざまなコンテナー エスケープ手段に活用することができます。

名前空間

名前空間についての Linux man ページ は以下のように述べています。

名前空間はグローバル システム リソースを抽象化してラップします。これにより、名前空間内のプロセスからは、自分専用の隔離されたグローバル リソースのインスタンスを持っているかのように見えます。グローバル リソースへの変更は、その名前空間のメンバーであるプロセスからは見えますが、それ以外のプロセスからは見えません。名前空間の用途の 1 つはコンテナーの実装です。

プロセス管理においてケイパビリティはあるプロセスが「」を実行できるのかを定義し、名前空間はそれらのアクションを「どこ」で実行できるのかを定義します。言ってしまえば名前空間とは、「あるプロセスとその子プロセスがグローバル リソース内に独自の排他的インスタンスを所有しているかのように動作できるようにする抽象化レイヤー」です。

さまざまな種類の名前空間が存在し、それぞれがオペレーティング システム (OS) 内で特定の種類のグローバル リソースを受け持っています。

いちばんわかりやすい名前空間の 1 つは、PID (プロセス識別子) 名前空間です。管理者またはソフトウェアが新しい PID 名前空間を作成すると、OS は名前空間の作成を担当するプロセスに PID 1 を割り当てます。次に OS は次の PID である 2 を最初の子プロセスに割り当て、3 を 2 番目の子プロセスに割り当て、4 を 3 番目の子プロセスに割り当て、というように割り当てていきます。

あるプロセスが root 権限で実行されていて cap_kill ケイパビリティをもっている、というシナリオを考えてみましょう。この場合、このプロセスは権限のチェックを回避し、ほぼすべてのプロセスを終了できます。ただし、このプロセスが新しい PID 名前空間内で動作している場合、そのプロセスのプロセス終了能力は同一名前空間内のプロセスに対してに限られます。cap_kill ケイパビリティを持つこの元のプロセスにとって、自身の PID 名前空間外部にあるプロセスは本質的に存在しないのです。

基本的に名前空間は隔離強制メカニズムとして機能するもので、ケイパビリティや seccomp などの追加機能を備えることにより、意図せずほかの名前空間に干渉したりエスケープしたりしないようにしています。

下の図 2 は、利用可能な Linux の名前空間を示しています。詳しくは名前空間に関する Linux の man ページに記載されています。

これは Linux の名前空間の詳細を示した表です。Namespace (名前空間)、Flag (フラグ)、Page (ページ)、Isolates (隔離) の各列が表示されています。行には、IPC、Network (ネットワーク)、Mount (マウント)、PID、Time (時間)、User (ユーザー)、UTS が含まれていて、それぞれ対応するフラグ、参照される man ページ、隔離される対象とペアになっています。
図 2. 利用可能な Linux 名前空間のリストとその簡単な説明

コンテナー エスケープ

コンテナー エスケープというと「ホスト システム上のコンテナー内でプログラムを実行する能力」だけを連想する方がおられるかもしれませんが、コンテナー エスケープ技術がどれもこの枠に収まるわけではありません。コンテナー エスケープのシナリオには、攻撃者がコンテナーを使ってホストからデータを盗んだり、特権昇格を実行したりすることも含まれます。

コンテナー エスケープ技術の例をいくつか見てみましょう。

例 1: ユーザーモード ヘルパー

最初の例は、ユーザーモード ヘルパーと呼ばれる一連の技術です。この例は call_usermodehelper カーネル関数を悪用することからその名が付きました。

ユーザーモード ヘルパー攻撃技術のしくみ

ドライバー向けに用意されている call_usermodehelper 関数は、カーネルから直接ユーザーモードのアプリケーションを準備して開始することで、カーネルがユーザーモードで稼働する任意のプログラムを昇格された権限で実行できるようにします。

ただし特定の条件下では、ユーザーはドライバーそのほかのカーネル モード コンポーネントに、同じ昇格された権限でユーザーモードのプログラムを実行させることができます。ユーザーモード ヘルパーという用語は、カーネルがこうした特定の条件下でユーザーモード ファイルに定義されたユーザーモード プログラムを実行するさまざまな状況を含意しています。

ここで強調しておきたいのが、攻撃者がユーザーモードで特定のファイルを作成・変更すれば、カーネルを騙してさまざまなプログラムを root 権限で実行できるという点です。これには root アクセスが必要ですが、攻撃者が昇格された権限か悪用可能な脆弱性を突いてコンテナーの制御を奪った場合、その攻撃者が必要なアクションをとるのは容易です。

ユーザーモード ヘルパー: release_agent

このユーザーモード ヘルパー技術は、cgroup とその release_agent ファイルを活用してコンテナー エスケープを実現します。私たちは過去に cgroup に影響する脆弱性について報告していますが、今回のコンテナー エスケープ技術は脆弱性に基づくものではありません。root 権限を持つ攻撃者がこのユーザーモード ヘルパー技術を使ってコンテナー エスケープを実現するというものです。cgroups はプロセスへのリソース割り当て調整に使われていて、リソースの使用を制限する手段を提供しています。

今回の例では、cgroup の release_agent のエスケープに、2019 年の Black Hat USA カンファレンスで、Brandon Edwards 氏と Nick Freeman 氏により最初に発表された [PDF] 技術を用います。特定の cgroup の release_agent を有効にすれば、対象 cgroup が空になったときに攻撃者はプログラムを実行できます。Linux は cgroups の適切なクリーンアップのためのこの機能を含めていますが、OS は何ら厳密な制約を持っておらず、任意の実行可能ファイルを実行可能です。

この技術の実装には次の手順が含まれます。

  1. ディレクトリーを 1 つ作成してそれをマウントし、cgroup を 1 つ割り当てます。
  2. その cgroup 内にディレクトリーを作成して新たなグループを作ります。
  3. notify_on_release ファイルの内容を 1 に設定します。これにより、ユーザーモード ヘルパーのメカニズム (すべての新しい cgroup に存在) が有効になります。
  4. release_agent ファイル内で実行可能ファイルの絶対パスを指定します。このファイルはすべての種類の cgroup のルート ディレクトリーに存在していて、全 cgroups 間で共有されます。ルート ディレクトリーの絶対パスはコンテナー内から /etc/mtab ファイルを照会すれば取得できます (図 3 参照)。
  5. cgroup.procs ファイルに 0 を書き込んでグループを空にします。そのグループが初期状態で空でも、release_agent で指定された実行可能ファイルは実行されます。

以下の図 3 は、簡潔なシェル コマンドのシーケンスを使ってこの技術を実装した例を示しています。

白で表示された複数行のコードには、さまざまな Linux ターミナル コマンドと、システム設定の変更およびネットワーク攻撃のシミュレーションを目的としたスクリプトが含まれています。
図 3. シェル コマンドで release_agent エスケープを実装したところ (出典: A compendium of container escapes - Brandon Edwards and Nick Freeman - Black Hat USA 19 [PDF])
これは、正当なユーザーモード ヘルパーを使って、いくつかのシェル コマンドを実行するだけでコンテナーをエスケープした例です。

コンテナー エスケープのためのそのほかのユーザーモード ヘルパー技術も、この例と似たパターンにならいます。ここ重要なのは、「コンテナー内から関連ファイルを変更できるならホスト システム上で root 権限で任意のプログラムを実行できる」という点です。

私たちの調査は、ユーザーモード ヘルパー技術が最も大きな影響を与えうることを示しています。その主な理由は、コンテナー エスケープが比較的容易なこと、うまく実装できた場合の影響が大きいことです。

ユーザーモード ヘルパー攻撃技術の検出方法

これら一連の技術の検出には体系的アプローチが求められます。

  1. call_usermodehelper 呼び出しのマッピング: 最初にカーネルが使う call_usermodehelper の全呼び出しを網羅した一覧を作成します。
  2. 影響を受ける呼び出しの特定: どの call_usermodehelper 呼び出しがファイル経由でユーザーモード プログラムから操作されうるかを見定めます。
  3. コンテナーの変更の評価: これらのファイルをコンテナー内から変更し、指定したプログラムを実行できるか調べます。
  4. ユーザーモード ヘルパー ファイルの監視: 下準備が整ったら、各ユーザーモード ヘルパーに関連付けられた関連ファイルへの変更を検出戦略が監視することになります。ここではとくに、コンテナーのユーザーモード プログラム内から発生した変更の識別が重要なポイントとなります。

こうした多段階プロセスを踏むことが、コンテナー内のユーザーモード ヘルパー悪用にからむ潜在的セキュリティ リスクの事前的検出・緩和能力向上につながります。

実地でのユーザーモード ヘルパー攻撃技術の検出

下の図 4 は、DEEPCE リポジトリーから得た deepce.sh という侵入テストツールで release_agent ファイルを変更し、コンテナーをエスケープしようとしたところを Cortex XDR が特定した様子です。

この画像は、あるコンテナー テクノロジー システムに対するサイバーセキュリティ攻撃を示したフローチャートです。この図は、「yosef/Ubuntu-20/root」というラベルの付いたノードで始まり、「deepce.sh」で終わっています。これら 2 つは危険または重要なポイントを表す 2 つの赤いアイコンで示されています。このプロセスは矢印で連結された複数のステップで進みます。「CMD」から始まり、「runC」を経て、最後にスクリプト「bash」と「deepce.sh」を実行しています。各ノードと遷移には、システム内でのアクションの順序とその性質を示すため、明確なラベルが付けられています。図の下には、コマンド ライン命令の「bin/sh ./deepce.sh --no-enumeration --exploit PRIVILEGED --username deepce --password deepce」が表示されています。
図 4. この画像は、あるコンテナー テクノロジー システムに対するサイバーセキュリティ攻撃を示したフローチャートです。この図は、「yosef/Ubuntu-20/root」というラベルの付いたノードで始まり、「deepce.sh」で終わっています。これら 2 つは危険または重要なポイントを表す 2 つの赤いアイコンで示されています。このプロセスは矢印で連結された複数のステップで進みます。「CMD」から始まり、「runC」を経て、最後にスクリプト「bash」と「deepce.sh」を実行しています。各ノードと遷移には、システム内でのアクションの順序とその性質を示すため、明確なラベルが付けられています。図の下には、コマンド ライン命令の「bin/sh ./deepce.sh --no-enumeration --exploit PRIVILEGED --username deepce --password deepce」が表示されています。 図 4. DEEPCE を使った release_agent のコンテナー エスケープ試行でトリガーされた Cortex XDR のアラート

図 4 は Cortex XDR のインシデント レポート内のアラートの因果関係チェーンを示した図で、イベントに関する洞察を提供しています。このアラートは指定されたツールによるプロセス実行ツリーを明示し、どの段階でアクティビティが検出され、その実行が阻止されたかを示しています。図 4 の Cortex XDR アラートはそのツールのコマンド ラインも合わせて表示することでツール実行にまつわる詳細なコンテキストを提供しています。

例 2: SUID を使用した特権昇格

コンテナーのセキュリティは、本稿前半で説明したメカニズム (ケイパビリティ、名前空間、seccomp など) で強化されているので、多くのコンテナーはホスト上で root 権限で動作できます。この技術はそこを突くものです。

SUID 攻撃技術のしくみ

この技術を使えば、あるホスト上で限定的な権限を持っているユーザーが、そのホスト上に存在する root 権限で動くプログラムを、コンテナーの内部から実行できるようになります。攻撃者がホストへの初期アクセスを持っていることが前提なので、これは完全なコンテナー エスケープではありません。ただし、最初はごく限られた権限しか持っていない攻撃者でも、これを使えばそのホスト上で root レベルの権限でアクションを実行できるようになります。

攻撃者がこのエスカレーションを実現できる理由は、あるコンテナーがホストと同じユーザー名前空間で動作している場合、そのコンテナー内のファイルに設定された SUID/GUID 権限ビットが、コンテナー外でもその権限を保持するからです。これは多くのコンテナー環境でよくある設定です。

この攻撃の実行には以下が必要です。

  • ホストと同じユーザー名前空間内で root として実行されているコンテナー
  • ホストとコンテナーの両方からアクセス可能なディレクトリー
  • ホスト上のシェル
  • コンテナー上のシェル

この技術を使う攻撃者は以下の手順を踏みます。

  1. コンテナーとホストが共有している既存のディレクトリーに、実行可能ファイルを作成します。
    攻撃者はコンテナー側、ホスト側のいずれの側からでもこのファイルを作成できます。
  2. コンテナー内から SUID 権限ビットを追加します。
  3. コンテナー外部から SUID を持つバイナリーを実行します。

これらの手順が完了すると、攻撃者の実行可能ファイルはそのホスト上で root 権限で動作します。

この前提条件が満たされているなら、攻撃者にとってこの攻撃は容易です。ファイルへの SUID 権限ビット設定は簡単な手順で、以下の chmod コマンドを使うだけですみます。

chmod u+s <ファイル名>

SUID 攻撃技術の検出方法

これは非常に特殊な攻撃技術なので、攻撃の重要段階に的を絞った検出アプローチが使えます。

  • ファイル作成: 実行が目的のファイル作成を監視します。
  • SUID/GUID ビットの変更: コンテナーとそのホストが共有しているディレクトリーのファイルに SUID/GUID ビットを追加するようなコンテナー内の chmod 操作を検出します。
  • コンテナー外でのファイルの実行: SUID/GUID ビットが設定されたファイルが、非 root のユーザーによってホスト上で実行されているようなインスタンスを検出します。

実地での SUID 攻撃技術検出

図 5 は、SUID 技術を使ったコンテナー エスケープ試行を検出・ブロックした Cortex XDR からのアラートです。

図 5. Cortex XDR のアラート。SUID 技術を使ったコンテナー エスケープの試みを示している

Cortex XDR はコンテナー ランタイム環境 (runc) からの bash インターフェイス経由の chmod コマンドにアラートを発報しています (図 5)。この chmod コマンドは、コンテナーとホストが共有しているディレクトリー内のファイルに、SUID 権限ビットを設定しようとしていました。

例 3: ランタイム ソケット

コンテナー インフラはホスト環境内ではクライアント/サーバー モデルで動いています。Docker などのコンテナー プラットフォームのドキュメントが説明しているように、コンテナー CLI がクライアントとして機能する一方、コンテナーのデーモンはサーバーとして機能します。図 6 は Docker アーキテクチャの概要を示したもので、これを見るとコンテナー環境のクライアント/サーバー型の特性がわかりやすいです。

クライアント、Docker ホスト、レジストリーなどのコンポーネントを含む Docker アーキテクチャを示した図。クライアント側には、「docker run」、「docker build」、「docker pull」などのコマンド例が表示されています。Docker ホストには、さまざまな構成を示す Docker デーモン、イメージ、およびコンテナーが表示されています。レジストリーには、NGINX とその関連項目 (データベースのアイコン) が示されているほか、「Extensions」、「Plugins」と書かれたフォルダーも表示されています。矢印は、これらのオブジェクト間でのコマンドやデータの流れを示しています。
図 6. Docker インフラのアーキテクチャ (出典: Docker ドキュメント)

このクライアント/サーバー インフラを実装しているランタイム ライブラリーは、API サーバーを外部に公開していて、この API サーバーがクライアント/サーバー間の通信を処理しています。このさいの通信はランタイム ソケットと呼ばれる Unix ソケットを介して行われます。攻撃者は、対象コンテナー内からそのコンテナーのランタイム ソケットと直接対話することで、このメカニズムを利用できます。

ランタイム ソケットの攻撃技術のしくみ

この技術を使うと、攻撃者は同一ホスト上に新たな特権つきコンテナーを作成できるようになります。作成後はその新しいコンテナーを使ってホスト側へとエスケープできます。

ランタイム ソケットがコンテナー内にマウントされている場合、API サーバーに直接コマンドを送信することでコンテナー ランタイムを制御できるようになります。このランタイム ソケットを使ってコンテナー ランタイムの制御を確立した攻撃者は、その Unix ソケット ファイル を使って API コマンドを実行できるようになります。これにより、攻撃者は容易に新たなコンテナーを作成し、そこからエスケープしてホスト側へアクセスできるようになります。

Unix ソケット ファイルを使ったランタイム ソケットとのやりとりは、次のアクティビティにより達成できます。

  • ランタイム ソケットをパラメーターに指定してコンテナー ランタイム CLI を介する方法
  • curl などの実行ファイルを使って任意のソケットを介して通信する方法

前者のアプローチだと、攻撃者は REST API の呼び出しをしなくても通常のコマンドを実行できるようになります。ただし、コンテナー ランタイムを識別してコンテナー内でそのコンテナー ランタイムの CLI を取得するのはひと仕事でしょう。

逆に、 curl のようなよくある実行可能ファイルを使うことにも利点があります。というのも、ほとんどのコンテナー環境にはそれらのファイルが既に存在しているからです。この方法の場合より複雑な REST API コマンドが必要になりますが、API サーバーと通信するための追加プログラムをインストールする必要がなくなります。

以下は、Docker の REST API を使ってコンテナー ランタイムと対話する curl コマンドの例です。これらの例では、攻撃者が新しいコンテナーを作成して起動しています。

  • curl --unix-socket /var/run/docker.sock http://localhost/containers/json
    • 作成されているすべてのコンテナーの情報を取得
  • curl -H "Content-Type: application/json" --unix-socket /var/run/docker.sock -d {json_containing_container_configuration} http://localhost/containers/create
    • 指定された JSON 構成に基づいてコンテナーを作成
  • curl --unix-socket /var/run/docker.sock http://localhost/containers/{container_id}/start
    • {container_id} で指定されているコンテナーを起動

このランタイム ソケット技術を使用すると、攻撃者はホストのルート ディレクトリーへのマウント ポイントを持つ特権付きコンテナーを作成できます。攻撃者はこの後、ホストのファイル システムへの特権アクセスを通じて新しく作成されたコンテナーからエスケープできます。

ランタイム ソケット攻撃技術の検出方法

この形式の攻撃は複数の方法で検出できます。

  • ランタイム Unix ソケットの監視: 最も直接的なアプローチはコンテナー ランタイム Unix ソケットへのリクエストを監視し、それらのリクエストがコンテナー内から出されたかどうかを確認することです。コンテナーの作成や操作など、影響のあるリクエストのみをフィルタリングすることで誤検知 (FP) を減らせます。
  • Unix ソケット ファイルのアクセス検出: 別の方法として、Unix ソケット ファイルへのアクセスを検出する方法があります。ただしこのアプローチには誤検知がつきものです。リクエストに対して完全な可視性がない状態で、関係ないインスタンスを除外するのは難しいためです。
  • CLI または curl コマンドの実行: コンテナー内部からのコンテナー ランタイム ソケットを使ったコンテナー ランタイム CLI または curl コマンドの実行の識別に重点を置いて検出を行うこともできます。この方法は効果的ですが、すべてのユース ケースを捕捉できるとは限りません。
  • 検索試行の検出: コンテナー内からのコンテナー ランタイム ソケット検索試行を検出するという別のアプローチもあります。ただしこれもほかの方法と同様、すべてのユース ケースを網羅できない可能性があります。

検出能力を強化するにはこれらの方法を組み合わせて使うことです。それによりカバレッジを最適化する多層防御戦略を実現できます。

実地でのランタイム ソケット攻撃技術検出

以下の図 7 は、侵入テスト ツール DEEPCE を使った攻撃を Cortex XDR が検出・防止したさいのアラートです。curl を使ってマウントしたコンテナー ソケットからコンテナーをエスケープしようとしています。

この画像は、セキュリティ侵害の試みを示すサイバーセキュリティ ネットワーク フロー図です。この図には、CGO と書かれた四角形、runc というラベルのついた円、XDR エージェント、bash シェルなどのさまざまなコンポーネントが描かれていて、これらのコンポーネントは「deepce.sh」というスクリプトに向かう方向つき矢印で接続されています。これにより、侵害試行の流れが表わされています。深刻度レベルの高いアラート アイコンと、侵入が阻止されたことを示す「Prevented (Blocked)」と書かれた追加の詳細も表示されています。下部のコンソールには、観測された動作の詳細が表示されていて、「Anomaly Detection (異常を検出)」、「Container escaping Protection (コンテナー エスケープの保護)」などのカテゴリーが表示されています。特定の技術データ、パス、識別子は、構造化されたテーブル形式でレイアウトされています。背景には、ディレクトリー パス「/yosef/Ubuntu-20/root」を持つコンピューター インターフェイスが表示されています。タイムスタンプ、ソース タグなどの重要な詳細と、各モジュールのアクティビティの簡潔な説明により、表示されているセキュリティ イベントのコンテキストがわかりやすくなっています。
図 7. Cortex XDR のアラート。ランタイム ソケット技術によるコンテナー エスケープ試行を示している

例 4: ログ マウント

これは Kubernetes に特有の攻撃で、より正確にはポッド エスケープと呼ばれるものです。というのも、Kubernetes プラットフォームはコンテナーを「ポッド (pod)」と呼んでいますし、この攻撃では Kubernetes 特有の機能を使ってコンテナーからエスケープするからです。本技術については、2019 年に Aqua Security が洞察に富む記事を公開しています。

ログ マウント攻撃技術のしくみ

この攻撃はポッド内にいる攻撃者に、root 権限を持つホスト上の任意のディレクトリーないしファイルへの読み取りアクセス権を与える可能性があります。この技術の要件は次のとおりです。

  1. ホストの /var/log ディレクトリーへのマウントをもつポッドにアクセスできる
  2. Kubernetes インターフェースを使ってログを読み取るケイパビリティがある
    1. これはログ アクセスを持つ通常の Kubernetes ユーザーとして実現可能
    2. 代わりにログ アクセスを持つポッド サービス アカウントを使ってもよい

最善のシナリオではホストの /var/log へのマウントをもつポッド内からログにアクセスできるようになります。

この脆弱性は Kubernetes がポッド ログにアクセスする方法に依るものです。各ポッドは /var/log 内に対応するログ ファイルを 1 つ持っています。このログ ファイルは、シンボリック リンク (symlink) によって、 /var/lib/docker/containers にあるコンテナー ディレクトリ内のログ ファイルにリンクされています。

この問題は kubelet が宛先を検証せずにシンボリック リンクの内容を読み取ってしまう方法に起因しています。たとえば、シンボリック リンクの宛先をログ ファイルから /etc/shadow へに変更することで、攻撃者がホストの /etc/shadow ファイルにアクセスできるようになります。

攻撃はそこでは終わりません。Kubernete の kubectl コマンドライン ツールを介して HTTP POST リクエストを生成する場合、このツールは裏では /var/log ディレクトリーから対象のログ ファイルへの相対パスを指定してログにアクセスしています。つまり、攻撃者が /var/log 内からルート ディレクトリーへのシンボリック リンクを作成した場合、攻撃者は root 権限でファイル システム全体にアクセスできるようになります。

たとえば、/var/log 内にある root_host という名前のホストのルート ディレクトリーへのシンボリック リンクと、ログ ファイル root_host/etc/passwd を指定する HTTP POST 要求を組み合わせると、攻撃者はホストの /etc/passwd ファイルを取得できるようになります。

この技術では「/var/log がマウントされたポッド」と「ログの読み取りケイパビリティを持つ Kubernetes アカウント」の両方へのアクセスを得る必要があるのでこれは簡単な作業ではありませんが、可能性は残ります。

ログ マウント攻撃技術の検出方法

この形式の攻撃は次の 2 つの方法で検出できます。

  • HTTP リクエストの監視:ログの読み取りを目的としたすべての HTTP 要求を監視し、不適切なパスをフィルタリングします。ただし、このアプローチでは、正当なログのシンボリック リンクを変更する攻撃を識別できない可能性があります。
  • シンボリック リンクの作成/変更の検出: ポッド内部から発生した、ホストの /var/log ディレクトリー内で作成・変更されたシンボリック リンクを検出します。これを実装するには、ポッド側でなくホスト側の /var/log ディレクトリーで発生する書き込み操作を確実に検出せねばなりません。

これら 2 つの検出方法を組み合わせることでこうしたログ マウントの検出を改善できます。

実地でのログ マウント攻撃技術検出

図 8 は、この技術を使った Kubernetes ポッドからのコンテナー エスケープ試行を検出・ブロックした Cortex XDR からのアラートです。このアラートは、ホスト ファイル システムにアクセスするため、/var/log にシンボリック リンクの作成が試行されたことを示しています。gこの試みでは、bash シェルを使って ln コマンドを実行し、シンボリック リンクを作成しようとしています。

これはサイバーセキュリティ プロセス フロー図で、番号の付いた円いアイコンが線でつながれ、4 つのステップを示しています。各ステップには、「CGO」、「runc」、「bash」、「ln」というラベルが付けられています。これらのラベルは、ソフトウェア セキュリティ チェックのさまざまな段階を表しています。この図は「yosef-Ubuntu-root」というタイトルの GUI に表示されていて、タイムスタンプ、ユーザー パス、セキュリティ署名などの追加の詳細が表示されています。最後のステップでは、ブロックされたアクションの通知が緑色のボックスで表示されています。
図 8. /var/log を使用したログ マウント エスケープ試行に関する Cortex XDR のアラート データ

例 5: センシティブ マウント

この技術はコンテナー内にマウントされている機微な宛先を持つディレクトリー (ホストの /etc ディレクトリーなど) にフォーカスしています。こうした宛先からはホストの /etc/passwd ファイルなどの個人情報を含むファイルへのアクセスが得られることから、攻撃者にとっては魅力的です。この種のマウントは構成ミスであって、こうしたマウント ポイントは「センシティブ マウント」と呼ばれます。

これは構成ミスの悪用にすぎませんが、コンテナー エスケープ技術の範疇に入るものです。

センシティブ マウント攻撃技術のしくみ

この技術に必要なアクションは、構成ミスのあるコンテナー内からこうしたセンシティブなマウントを検出し、それらにアクセスすることのみです。たとえば攻撃者がホストの /etc ディレクトリーにアクセスする /host_etc という名前のマウントを使ってコンテナーへのアクセスを得る可能性があります。攻撃者は、構成ミスのあるコンテナーから /host_etc/password にアクセスすることにより、事実上ホストの /etc/passwd ファイルにアクセスしたことになります。

この技術は最も簡単なコンテナー エスケープ方法ですが検出は困難です。

センシティブ マウント攻撃技術の検出方法

機微情報を含むディレクトリーをマウントするコンテナーを監視してアラートを出すことは可能ですが、これは能動的な保護とはいえません。

この技術への効果的な保護には、事前に決められた機微ファイルや場所へのあらゆるアクセス (読み取り、書き込み、作成、削除) を検出する必要があります。ところがこの戦略では誤検知が急増するリスクがあり、重大な懸念が生じます。検出されたファイル アクセスがホスト上の正しいファイルに対応していることを確認する必要があります。

たとえば、/etc/shadow は不正アクセスから守るべき機微ファイルの一例です。コンテナー ランタイムは通常、ホスト ファイル システム内の指定の場所に新しいコンテナーのルート ディレクトリーを設定します。これにあたっては chroot または pivot_root が使われて、コンテナーからの適切なアクセス レベルが設定されます。つまりコンテナーの /etc/shadow ファイルはホストの /etc/shadow ファイルと同じファイルではないので、コンテナーの /etc/shadow を直接監視しても、攻撃を検出する上では何の価値もありません。

shadow」という名前の付いたすべてのファイルへのアクセスを検出するのも別の問題をもたらします。マウントは元のパスを保持していないことや、完全パスの情報が示されないことがあります。

解決策としては、検出された各ファイル アクセスのパスをコンテナー パスから対応するホストのパスへ変換する方法があります。これにより、ホストのパスに基づいた監視が可能になり、コンテナーとホスト間で直接共有すべきでない機微なファイルやディレクトリーへの攻撃を正確に検出できるようになります。このソリューションは概念的には単純ですが、実装は難しいかもしれません。

この種のコンテナー エスケープ手法に対し、私たちはどのように防御すればよいのでしょうか。課題は「コンテナー内でマウントされているファイルのどれがホスト上の機微ファイルと対応しているかを知る」という点です。Cortex XDR は、関連するイベントのパスを変換し、これらのセンシティブ マウントからのファイル アクセスをリアルタイムで検出することで、この課題に対応しています。

実地でのセンシティブ マウント攻撃技術検出

図 9 は、センシティブ マウント技術を使ったコンテナー エスケープ試行を検出・ブロックした Cortex XDR からのアラートです。これは、bash インターフェイスを使い、構成ミスのあるコンテナー上のセンシティブ マウントを介してホスト上の機微ファイルにアクセスしようとした試みを Cortex XDR が検出したところです。

図 9. センシティブ マウント技術を使ったエスケープ試行に関する Cortex XDR のアラート データ

検証環境

私たちは検証環境内で containerd コンテナー ランタイムを使う Kubernetes クラスターを選択しました。containerd は現在 Docker Engine で使われているコンテナー ランタイムであるという点は注目に値します。

本稿で検討してきた技術と Cortex XDR に組み込んだカバレッジは、特定のコンテナー ランタイムに依存するものではありません。弊社のアプローチにより、検出と保護が多様なコンテナー ランタイムに適用され、さまざまなランタイム環境での柔軟性と有効性が維持されます。

結論

本稿ではさまざまなコンテナー エスケープ技術を検討してきました。本稿の結果はコンテナー技術の人気が高まるなかでの攻撃リスクの高まりを強調するものといえるでしょう。そのなかには攻撃者にコンテナーのホストへの部分的アクセス権を与える技術も、攻撃者にホストへの完全なアクセス権を与える技術もありました。コンテナーを使う組織が増えるにつれて、こうしたエスケープ技術からのリスクは、脅威情勢において注目すべき特性の 1 つでありつづけることでしょう。

潜在的な攻撃の緩和に向け、全コンテナー利用者は、こうした技術のリスクを認識し、推奨されるセキュリティと検出のガイドラインを遵守せねばなりません。

私たちは本稿に解説した検出原理に基づき、Cortex XDR に堅牢な検出ロジックを組み込み済みです。

パロアルトネットワークスのお客様は、Cortex XDRXSIAM Linux AgentCortex XDR agent for CloudPrisma Cloud Defender Agent を通じ、「コンテナー エスケープ」モジュールを使ってこれらのコンテナー エスケープ技術からより適切な保護を受けられます。

侵害の懸念があり弊社にインシデントレスポンスに関するご相談をなさりたい場合は、infojapan@paloaltonetworks.com までメールにてご連絡いただくか、下記の電話番号までお問い合わせください(ご相談は弊社製品のお客さまには限定されません)。

  • 北米フリーダイヤル: 866.486.4842 (866.4.UNIT42)
  • EMEA: +31.20.299.3130
  • APAC: +65.6983.8730
  • 日本: (+81) 50-1790-0200

パロアルトネットワークスは、これらの調査結果を Cyber Threat Alliance (CTA: サイバー脅威アライアンス) のメンバーと共有しました。CTA のメンバーはこのインテリジェンスを使って、お客さまに保護を迅速に提供し、悪意のあるサイバー攻撃者を体系的に阻害できます。詳細は Cyber Threat Alliance にてご確認ください。

追加リソース

2024-08-07 09:30 JST 英語版更新日 2024-08-06 09:40 PDT の内容を反映し破損していたリンクを修正

Enlarged Image