Falcoでコンテナエスケープの振る舞いを検出する方法

By 清水 孝郎 - JUNE 21, 2022

SHARE:

本文の内容は、2022年6月21日にStefano Chiericiが投稿したブログ(https://sysdig.com/blog/container-escape-capabilities-falco-detection/)を元に日本語に翻訳・再構成した内容となっております。

攻撃者は、コンテナをコントロールすることに成功すると、コンテナエスケープのテクニックを使用できるようになるので、彼らが引き起こすことができる影響ははるかに大きくなります。これが、infosecにおいて繰り返し取り上げられる理由であり、それを検知する Falco のようなツールが非常に重要である理由です。

コンテナ技術は、ネームスペース、cgroups、SecCompフィルター機能などのさまざまな機能を利用して、同じホスト上で動作するサービスを分離し、最小特権の原則を適用します。

container escape - Falco detect capabilities
ケイパビリティは、コンテナが持つことのできるアクセスレベルを制限する方法を提供し、ルートユーザの力をより粒度の細かい単位に分割するものです。しかし、それらはしばしば誤設定され、プロセスやスレッドに過剰な特権を付与してしまいます。

近年発表されたCVEでは、それらの機能が誤って設定され、攻撃者がコンテナやホスト内部で特権をエスケープすることにつながる可能性があることが指摘されています。ここでは、コンテナ脱走の脆弱性をいくつか示します。

  • CVE-2022-0847: “Dirty Pipe” による Linux のローカル特権のエスカレーション
  • CVE-2022-0492: コンテナのエスケープによる特権の昇格の脆弱性
  • CVE-2022-0185: コンテナのエスケープを引き起こす Linux カーネルの脆弱性の検出と緩和
  • CVE-2019-5736: runc コンテナのブレイクアウト
  • CVE-2022-0811: CRI-Oに影響する任意のコード実行

この記事では、よく知られたコンテナのエスケープ技術を分析し、Falcoを使用してケイパビリティを検出および監視する方法について説明します。

ケイパビリティとは何か?

Linuxのドキュメントでは、capabilities((ケイパビリティ)を以下のように明確に定義しています。

” カーネル 2.2 以降、Linux は伝統的にスーパーユーザーに関連する特権を、独立に有効化および無効化できるケイパビリティと呼ばれる個別のユニットに分割しています。ケイパビリティはスレッドごとの属性である。”

Linux 3.2現在、41のケイパビリティがあり、Linuxのドキュメントでレポートされています。

つまり、capabilities(ケイパビリティ)はrootユーザの権限を細かく分割して、特定の特権タスクを実行するのに必要なだけの力をスレッドに付与するものです。仮にその断片が十分に小さく、うまく選ばれたとした場合、特権を持つプログラムが危険にさらされたとしても、考えられる被害は、そのプロセスが利用可能な一連のケイパビリティによって制限されます。

Snykによるデフォルトの機能で動作させた場合と、機能を制限した場合の違いを示した図
Container capabilities
利用可能なすべての機能のうち、特筆すべきはCAP_SYS_ADMINCAP_NET_ADMINで、これは非常に広範で寛容な機能です。

CAP_SYS_ADMINは、コンテナ内で特権的な操作が行われる場合、コンテナから落とすことが困難な管理操作を行うために必要です。広範な許可のため、追加能力または完全なルート(すべての能力への典型的なアクセス)に容易につながります。

CAP_NET_ADMIN は、インターフェース設定の変更、ホストファイアウォールの管理、プロミスキャスモードの設定など、ネットワーク関連のすべての操作の実行に必要です。このケイパビリティであっても、パーミッションが悪用された場合、潜在的な損害は甚大になる可能性があります。

定義上、隔離された環境であるコンテナでは、最も寛容な能力はすでにデフォルトで削除されています。つまり、追加の設定を指定せずにDockerコンテナを実行すると、Dockerは制限された一連の機能を使用することになります。

では、どこに問題があるのでしょうか?

先ほどの説明で重要なのは「小分け」であり、ここからが問題なのです。root権限を小さく分割することは、セキュリティの観点からは有効ですが、分割しすぎるのも困りものです。また、Linuxの開発モデルには、どのように能力を割り当てたり分割したりすべきかを決める中央の権威が存在しません。

この混乱は、どのように進めればよいかを理解しようとする開発者に、多くの疑念と誤解をもたらします。そのため、十分な情報がないまま、CAP_SYS_ADMINやそれに類する過剰な機能を新機能として選択することになるのです。

そして、現在に至っています。CAP_SYS_ADMINは新しいルートです。
Capabilities split explained - Falco detectケイパビリティの分割の説明 – Falco detect

一方では、ケイパビリティの目的は、特権プログラムのパワーをroot以下に制限することです。一方で、CAP_SYS_ADMINというプログラムがあれば、多かれ少なかれゲームは終了してしまうのです。

コンテナでは、一連の能力がデフォルトで削除されていても、コンテナの実行時に追加する能力を指定することで、能力のセットを拡張することが常に可能です。ご存知のように、コンテナは特権として直接実行することもでき、この場合、コンテナはCAP_SYS_ADMINを含む利用可能なすべての能力を使用することができます。

ハンズオン CAP_SYS_ADMIN

簡単な例を挙げます。unshare コマンドは、ホスト内に新しいネームスペースを作成するために使用します。このような操作は、コンテナが過剰な能力なしで実行されている場合は許可されず、実行すると、次のようになります。

stefano@stefano falco % docker run -it alpine:latest      
/ # cat /proc/kmsg
cat: can't open 'cat /proc/kmsg': Operation not permitted

代わりにCAP_SYS_ADMINケイパビリティでコンテナを実行すると、次のようになります。

stefano@stefano falco % docker run -it --cap-add CAP_SYS_ADMIN alpine:latest 
/ # cat /proc/kmsg
<4>[6226394.148135] printk: cat (980141): Attempt to access syslog with CAP_SYS_ADMIN but no CAP_SYSLOG (deprecated).

警告メッセージで指摘されているように、CAP_SYSLOGはCAP_SYS_ADMINから権限を分離するために作成されているため、このアクションを実行するには特定のケイパビリティを使用する必要があります。

stefano@stefano falco % docker run -it --cap-add CAP_SYSLOG alpine:latest 
/ # cat /proc/kmsg

最後の例でわかるように、適切なケイパビリティを使用することで、警告メッセージなしでファイルを開くことができます。

次に、CAP_SYS_ADMINが特定のアクションを実行するために実際に必要とされる別の例を見てみましょう。この例では、新しいネームスペースを作成するために、unshareコマンドを使用します(この場合、コンテナ内)。コマンドのドキュメントでレポートされているように、unshareは、動作とアクションの実行にCAP_SYS_ADMIN能力を必要とします。前回と同様に、ケイパビリティを追加せずにコンテナ内でコマンドを実行するとどうなるかを見てみましょう。

stefano@stefano falco % docker run -it alpine:latest      
/ # unshare
unshare: unshare(0x0): Operation not permitted

代わりにCAP_SYS_ADMINケイパビリティでコンテナを実行すると、次のようになります。

stefano@stefano falco % docker run -it --cap-add CAP_SYS_ADMIN alpine:latest 
/ # unshare
3b28503d0205:/#

上記の例でわかるように、特別な権限のおかげで新しいネームスペースを作成することができました。

最後の例で指摘したように、設計上CAP_SYS_ADMINを必要とする動作がいくつかあります。したがって、誤用や悪意のある行動があるかどうかを確認する唯一の方法は、スレッドとプロセスのケイパビリティを監視することです。

Falcoを使用したケイパビリティの監視

ありがたいことに、新しい Falco バージョン 0.32 では、スレッドケイパビリティを監視し、許可された能力だけが利用可能であることを確認することが可能です。

このタスクを達成するために、3つの新しいフィールドがFalcoに追加されました。

  • Thread.cap_permitted: スレッドが得ることのできるケイパビリティのスーパーセット
  • Thread.cap_inheritable: execveイベントの後、許可されたセットに入るかもしれないケイパビリティのセット
  • Thread.cap_effective: 実行に必要な許可チェックを実行するためにカーネルが使用するケイパビリティのセット
今回は、特権で実行されているコンテナ内にいるため、適用されているケイパビリティの一覧を簡単に確認することができます。cat /proc/self/status というコマンドを使用すると、適用されているcapの値を確認することができます。

CapInh:	00000000a82425fb
CapPrm:	00000000a82425fb
CapEff:	00000000a82425fb
CapBnd:	00000000a82425fb

結果の00000000a82425fbの値をcapshでデコードすると、ケイパビリティのリストが表示されます。

capsh --decode=00000000a82425fb
0x00000000a82425fb=cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_sys_admin,cap_mknod,cap_audit_write,cap_setfcap

中でも、有名なCAP_SYS_ADMINを見ることができます。

Falcoでこの情報を利用できるようにすることで、これらの機能に対する検出を作成し、誤った設定の機能が私たちの環境で適用された場合にアラートを上げることができます。

Falcoを使ったコンテナエスケープの検出

このシナリオでは、cgroup v1 virtual filesystem と CAP_SYS_ADMIN に依存する、よく知られたコンテナエスケープ技法が見られます。

この悪用法は、このブログで紹介されています。エスケープを実行するためには、以下のものが必要です。

  • コンテナ内でrootとして実行されている必要があります。
  • コンテナは、CAP_SYS_ADMIN Linuxケイパビリティで実行されている必要があります。
  • コンテナは、AppArmor プロファイルを持たないか、または mount システムコールを許可している必要があります。
  • cgroup v1 仮想ファイルシステムは、コンテナ内で読み書き可能にマウントされている必要があります。
特に、cgroup v1 は、root としてのコマンドの実行とコンテナのエスケープを実行するために悪用される 2 つのファイル notify_on_release と release_agent に依存しています。しかし、これらのファイルは、特権の昇格と隔離の解除という同じ目的を達成するために、他のエクスプロイトでも使用されています。

最近の例としては、CVE-2022-0492があります。

コンテナがこの機能を持ち、それが作成されたときに検出されなかった場合、私たちは最後の防衛線として、Falcoによるランタイムセキュリティを用意しています。

Falco detects container escapeFalcoはコンテナのエスケープを検出する

Falco とスレッドで利用可能な能力に対する新しい可視性を使用すると、過剰なケイパビリティを持つ脅威によってファイル release_agent が開かれ、変更されているかどうかを検出することができます。この場合、スレッドが有効なケイパビリティのセットに明示的にCAP_SYS_ADMINを含んでいるかどうかをチェックします。

- rule: Detect release_agent File Container Escapes
  desc: "This rule detects an attempt to exploit a container escape using release_agent file. By running a container with certains capabilities, a privileged user can modify release_agent file and escape from the container"
  condition:
    open_write and container and fd.name endswith release_agent and (user.uid=0 or thread.cap_effective contains CAP_DAC_OVERRIDE) and thread.cap_effective contains CAP_SYS_ADMIN
  output:
    "Detect an attempt to exploit a container escape using release_agent file (user=%user.name user_loginuid=%user.loginuid filename=%fd.name %container.info image=%container.image.repository:%container.image.tag cap_effective=%thread.cap_effective)"
  priority: CRITICAL
  tags: [container, mitre_privilege_escalation, mitre_lateral_movement]

このルールのおかげで、コンテナの分離を破ってノード全体を構成するために release_agent と過剰なケイパビリティを使用するすべてのテクニックに対して、強力でノイズのない検出を作成することができるのです。

10:11:27.415074914: Critical Detect an attempt to exploit a container escape using release_agent file (user=<NA> user_loginuid=-1 filename=/tmp/cgrp/release_agent cool_williamson (id=8ed46a770162) image=ubuntu:latest cap_effective=CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER CAP_FSETID CAP_KILL CAP_SETGID CAP_SETUID CAP_SETPCAP CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SYS_CHROOT CAP_SYS_ADMIN CAP_MKNOD CAP_AUDIT_WRITE CAP_SETFCAP)

まとめ

これまで見てきたように、誤設定や過剰なケイパビリティは新しい CVE の一部であることが多く、重大なセキュリティ問題を引き起こす可能性がありますが、ケイパビリティはコンテナを分離する方法を提供しています。

Falcoのようなツールを使えば、CAP_SYS_ADMINのような特定のケイパビリティが悪用されたときに監視することが可能です。ルールに新しいFalcoフィールドを使用することで、これらの悪意のある行動があなたの環境で起こったときにセキュリティアラートを上げ、フラグを受けることが可能になりました。




その後、もしFalcoについてもっと知りたいのであれば: