本文の内容は、2021年7月28日にAlberto Pellitteriが投稿したブログ(https://sysdig.com/blog/cve-2021-33909-sequoia-falco-linux-filesystem)を元に日本語に翻訳・再構成した内容となっております。
CVE-2021-33909(Sequoiaと命名)は、Linuxのファイルシステムに影響する新たな特権昇格の脆弱性です。2021年7月に公開され、2014年に多くのLinuxディストロで紹介されました。その中には、Ubuntu(20.04、20.10、21.04)、Debian 11、Fedora 34 Workstation、そしてRed Hat製品の一部も含まれています。
この脆弱性は、Linux カーネルの Filesystem レイヤーの seq_file に見られるout-of-bounds writeが原因です。
この脆弱性は、深刻度が高い (CVSS 7.0) ことを意味しており、低レベルの特権的な攻撃者によって悪用された場合、攻撃者は権限を昇格させて root になり、関係するマシンを危険にさらす可能性があります。
管理者権限を持つ攻撃者は、侵害されたマシンで保存および処理されるすべてのデータにアクセスできます。これには、顧客の個人情報や、より大規模な攻撃に使用される可能性のあるインフラストラクチャー内のサービスの認証情報や秘密情報などが含まれます。
この記事では、Sequoiaの脆弱性が特権昇格の実行に使用される理由と、その緩和方法について説明します。
予備知識
ファイルシステムとは、物理的なデバイスに保存されているデータとメタデータの集合体のことです。ファイルシステムの実装には、ext2、FAT、NFSなどのように、1つ1つの動作が大きく異なる種類があります。
異なるストレージデバイス上でこれらすべてをサポートするために、Linuxのファイルシステムアーキテクチャは、共通のAPI関数セットを提供しており、例えば、ユーザーは実際のファイルシステム実装とは無関係にファイルを読み書きすることができます。
このような理由から、Linuxのファイルシステムのインターフェースは、ユーザーインターフェース層、ファイルシステムの実装、そしてストレージデバイスのドライバーという3層構造で実装されています。
CVE-2021-33909は、ファイルシステム層におけるLinuxカーネルのseq_fileに直接影響を与えています。
それでは、このCVEの技術的な側面について深く掘り下げてみましょう。
CVE-2021-33909のSequoia問題について
コードネーム「Sequoia」と呼ばれる脆弱性 CVE-2021-33909 は、権限のない、または権限の低いローカルユーザーが root 権限に昇格したり、システムクラッシュを引き起こしたりすることが可能です。これは、size_tからintへの変換(64ビットから32ビットへの変換)における検証の欠落を利用して行われ、カーネルの内部情報が漏洩する可能性があります。実のところ、Sequoiaに関連する欠陥は、Linuxカーネルのファイルシステム層のseq_fileインターフェイスで見つかったout-of-bounds writeです。根本原因は以下の通りです:
- seq_fileインターフェースは、それぞれがレコードのシーケンスを含む仮想ファイルを生成します。
- 各レコードは seq_file バッファに収まらなければならず,そのサイズは size_t(64 ビットの符号なし値)である。必要であれば、このコードの最後にある左シフト操作からわかるように、2倍にすることで大きくすることができます。
/*grab buffer if we did not have one*/ if (!m->buf){ m->buf=kmalloc(m->size=PAGE_SIZE, GFP_KERNEL); } … /* we need at least one record in the buffer */ while(1){ … m->buf=kmalloc(m->size<<=1, GFP_KERNEL); }
実際に問題となるのは、show_mountinfo()関数で長いディレクトリパスを使用した場合です。実は、show_mountinfo()はseq_dentry()を呼び出し、そのseq_dentry()がそれぞれdentry_path()を呼び出します。
char* dentry_path (struct dentry* dentry, char* buf, int buflen)
プロトタイプを見ればわかるように、buflen(バッファの長さ)をint(32ビット符号付き値)として期待しており、size_tではありません。そのため、buflenは変換問題を起こし、数値を負の値に変換してしまいます。これにより、境界外アクセスの脆弱性が発生します。
CVE-2021-33909を利用するためには、低レベルの特権ユーザが以下の操作を行うエクスプロイトを使用する必要があります。
- 総パス長が1GBを超える深いディレクトリ構造を作成します。CVE-2021-33909は、まずbigdirというディレクトリを作成し、その中にforループで深いディレクトリ構造を生成します。
- そして、そのディレクトリを非特権ユーザーのネームスペースにバインドマウントし、最後に削除します。
- バインドマウントされたディレクトリのロングパスを読むために、/proc/self/mountinfoのopen()とread()を呼び出します。
- 小さな eBPF プログラムと組み合わせて使用することで、情報漏えいを引き起こし、限定的に制御された境界外書き込みで、カーネルメモリを読み書きする目的で使用されています。
CVE-2021-33909の影響について
CVE-2021-33909は、最近公表されたものであり、関連する脆弱性を公表する責任があるため、特権昇格のための公開されたエクスプロイトはまだ公表されていません。代わりに、システムクラッシュを引き起こす脆弱性の proof of concept が公開されています。CVSSシステムによると、この脆弱性のスコアは7.0で、深刻度が高いことを意味しています。
この脆弱性の深刻度が高い理由は、特権の昇格により、攻撃者がroot権限を取得できることです。つまり、攻撃者は、システム全体の整合性を損なう可能性のある、あらゆる種類の不正な実行や行為を行うことができるのです。攻撃者は、対象となるホストの内部に保存されている機密データにアクセスできるほか、OSやその設定を操作することもできます。
ちなみに、攻撃者は対象となるマシンの中で既に低レベルの権限を持っているはずで、これが重要とされていない理由です。
先に述べたように、この脆弱性は2014年以降、多くのLinuxディストリビューションに影響を与えているため、この脆弱性の影響を受けるマシンが多数存在することがわかります。
悪用される可能性があるため、私たちはこの問題をどのように軽減し、検出するかに注目する必要があります。
CVE-2021-33909を軽減する
もしあなたの環境がこの脆弱性の影響を受けているのであれば、できるだけ早く関連するパッチをインストールしてください。しかし、お使いのLinuxディストリビューションに対応したパッチがまだリリースされていない場合や、パッチをすぐにインストールできない場合は、ホストスキャンによってこの脆弱性を緩和することができます。
ホストスキャンでは、環境の各ホストの内容を分析して、セキュリティ上の問題や脆弱性、悪しき慣習を軽減することができます。
イメージスキャンのベストプラクティスをチェックして、このメカニズムがどのように既知の脆弱性が本番環境にデプロイされるのをブロックするのに役立つかを確認してください。また、脆弱性をどのように扱うかについては、脆弱性評価と管理のベストプラクティスをご覧ください。
以下の画像は、スキャン対象として選択されたホストがSequoia脆弱性の影響を受けている場合のスキャン結果を示しています。
Sysdig secureでのホストのスキャン結果
Sysdig secureは、脆弱性に関する情報を提供し、改善策を提案します。
CVE-2021-33909のエクスプロイト後の検出について
前述の通り、この脆弱性に対する公開されたエクスプロイトはリリースされていません。しかし、深刻度が高いため、Falcoを使用してエクスプロイト後の活動を検出することは非常に重要であると思われます。Falcoは、CNCFのオープンソースプロジェクトで、アプリケーションの予期せぬ動作を検出し、ランタイムでアラートを送信するために使用されます。事前に定義されたルールを使用することもできますが、必要に応じてカスタマイズしたり、新しいルールを作成したりすることもできます。
侵入後の活動を検出するために、ホスト内の高レベルの特権実行を監視するためのデフォルトのFalcoルールをいくつか見てみましょう。詳細については、GitHubのFalcoプロジェクトをご覧ください。
ルール: バイナリディレクトリ以下の書き込み
このルールでは、/binまたは/sbinフォルダ以下での疑わしい書き込み操作を検出します。このフォルダには、それぞれユーザーが実行可能なファイルや、bashシェルなどのバイナリ、およびシステム管理目的でルートユーザーが実行する重要なシステム管理バイナリが含まれています。- rule: Write below binary dir desc: an attempt to write to any file below a set of binary directories condition: > bin_dir and evt.dir = < and open_write and not package_mgmt_procs and not exe_running_docker_save and not python_running_get_pip and not python_running_ms_oms and not user_known_write_below_binary_dir_activities output: > File below a known binary directory opened for writing (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2] container_id=%container.id image=%container.image.repository) priority: ERROR tags: [filesystem, mitre_persistence]
ルール: /root以下への書き込み
root ユーザーのホームディレクトリである /root 内の書き込み操作を監視することができます。- rule: Write below root desc: an attempt to write to any file directly below / or /root condition: > root_dir and evt.dir = < and open_write and proc_name_exists and not fd.name in (known_root_files) and not fd.directory pmatch (known_root_directories) and not exe_running_docker_save and not gugent_writing_guestagent_log and not dse_writing_tmp and not zap_writing_state and not airflow_writing_state and not rpm_writing_root_rpmdb and not maven_writing_groovy and not chef_writing_conf and not kubectl_writing_state and not cassandra_writing_state and not galley_writing_state and not calico_writing_state and not rancher_writing_root and not runc_writing_exec_fifo and not mysqlsh_writing_state and not known_root_conditions and not user_known_write_root_conditions and not user_known_write_below_root_activities output: "File below / or /root opened for writing (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline parent=%proc.pname file=%fd.name program=%proc.name container_id=%container.id image=%container.image.repository)" priority: ERROR tags: [filesystem, mitre_persistence]
ルール:プライベートキーやパスワードの検索
攻撃者が機密データやファイルを見つけようとしているかどうかを検出します。- rule: Search Private Keys or Passwords desc: > Detect grep private keys or passwords activity. condition: > (spawned_process and ((grep_commands and private_key_or_password) or (proc.name = "find" and (proc.args contains "id_rsa" or proc.args contains "id_dsa"))) ) output: > Grep private keys or passwords activities found (user=%user.name command=%proc.cmdline container_id=%container.id container_name=%container.name image=%container.image.repository:%container.image.tag) priority: WARNING tags: [process, mitre_credential_access]
ルール: ssh情報の読み取り
このルールは、sshディレクトリ以下の読み取りの試みを検出します。- rule: Read ssh information desc: Any attempt to read files below ssh directories by non-ssh programs condition: > (consider_ssh_reads and (open_read or open_directory) and (user_ssh_directory or fd.name startswith /root/.ssh) and (not proc.name in (ssh_binaries))) output: > ssh-related file/directory read by non-ssh program (user=%user.name command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline) priority: ERROR tags: [filesystem, mitre_discovery]
まとめ
脆弱性CVE-2021-33909は、すでにホストに対してローカルで低権限のアクセス権を持っている攻撃者が、洗練されたエクスプロイトを使って特権昇格を実行し、root権限で任意のコマンドを実行したり、影響を受けるシステムをクラッシュさせたりすることを可能にします。このような脆弱なホストの実行を緩和したい場合、ホストスキャナーなどのツールを使用することができます。また、Falcoを採用して、ホスト内の疑わしいエクスプロイト後の動作を検出し、カスタムルールまたはデフォルトルールがトリガーされたときに、いくつかのアラートを受け取ることもできます。
ところで、もしあなたのホストがすでに実行されていて脆弱であるならば、高レベルの特権的行為や悪意のある行為からあなたを守るために、関連するパッチをインストールすることをためらわないでください。
Falcoについてもっと知りたい方は:
- Falco.orgで始める。
- GitHubでFalcoプロジェクトをチェックしてください。
- Falco コミュニティに参加する。
- Falco Slackでメンテナと交流する。
- ツイッターで @falco_org をフォローする。
Sysdig Secureは、他のオープンソースプロジェクトとともに、アウトオブボックスのルールでFalcoを拡張し、Kubernetesのセキュリティとの連携や管理をさらに容易にしています。30日間の無料トライアルに登録して、ご自身の目で確かめてください!