本文の内容は、2022年3月9日にJason Averyが投稿したブログ(https://sysdig.com/blog/cve-2022-0847-dirty-pipe-sysdig/)を元に日本語に翻訳・再構成した内容となっております。
CVE-2022-4092に続いて、Linux Kernelのローカル権限昇格の欠陥が月曜日に公開され、発見者は「Dirty Pipe」というニックネームを付けました。MITREは、これをCVE-2022-0847と命名しました。
「Dirty COW」エクスプロイト(CVE-2016-5195)と同様に、この欠陥はカーネルがパイプ内のページを管理する方法を悪用し、Linuxの最新バージョンに影響を及ぼします。本脆弱性は、非公式にCritically severeスコア8.8と評価されており、ローカル脆弱性としては極めて高いスコアとなっています。
このブログ記事では、この脆弱性とそこからの影響について、汚い部分をあまり深く掘り下げることなく説明したいと思います。
プログラムプラミング
Mitre CVE-2022-0847では、この脆弱性を次のように説明しています。“Linuxカーネルのcopy_page_to_iter_pipe関数とpush_pipe関数において、新しいパイプバッファ構造体の「flags」メンバーの初期化が適切でないため、古い値を含む可能性があるという欠陥が発見された。この欠陥により、権限のないローカルユーザーが、読み取り専用ファイルによってバックアップされたページキャッシュのページに書き込み、システム上で特権を昇格させることが可能です。”。よし、分解してみよう。
パイプとは何でしょうか?パイプとは、あるプログラムが他のプログラムにデータを送るための単純な方法です。
パイプは、プログラムが他のプログラムと通信する際に、データをディスクに書き込む必要がなく、一般的にプログラムを高速化することができる方法だと考えてください。CPUは、これらのデータの塊をメモリ上でページと呼ばれるデータセットで管理します(通常は4kB単位)。
ページスプライシングは、実際にデータをメモリに書き換えることなく、異なるパイプページ間でデータを結合するための性能上のトリックです。
ページがマージされるためには、ページキャッシュにPIPE_BUF_FLAG_CAN_MERGEフラグが設定されている必要があります。このフラグは、ページが満杯になったときにカーネルによって設定されます。その後、ページキャッシュが空になると、PIPE_BUF_FLAG_CAN_MERGEフラグは保持されます。これはすぐにわかるように、問題になることがあります。
台無しにする
さて、ではこの話はどのようにまとまるのでしょうか?発見者であるMax Kellermannが公開した情報には、バグに遭遇した経緯が長々と描かれています。要約すると、Linuxカーネルのメモリ管理機能において、パイプページキャッシュをマージし、他のページキャッシュを上書きすることができる欠陥が発見されました。この脆弱性は、Linux 5.8以降、パイプのページキャッシュのデータをマージして上書きすることが可能になり、初めてアクセス可能になったと開示されました。AppArmorやSeccompのようなシステム保護は、安全を確保するのに有効ですが、この脆弱性を利用されることを防ぐことはできません。
以下は、攻撃者がCVE-2022-0847を利用する方法です。
まず、何らかの手段でシステム上のシェルにアクセスする必要があります。これは、一般人のアカウントであったり、リモート攻撃に対して脆弱なサービスを実行するためのシステムアカウントであったりします。アクセスした後は、不正に上書きするために読むことができる興味深いファイルを見つける必要があります。例えば、/etcにあるパスワードファイルや設定ファイルなど、通常は読み取り専用になっているファイルは、攻撃者にとって格好の対象です。攻撃者は、パイプを開くプログラムを実行し、ページキャッシュをバイトで満たし、PIPE_BUF_FLAG_CAN_MERGEフラグを設定し、それを空にして上書きしたいデータで置き換えます。その後、splice()が呼ばれ、ページがマージされます。PIPE_BUF_FLAG_CAN_MERGE フラグにより、新しいデータは元のターゲットファイルにマージされ、読み取り専用の制限を回避することができます。
公開の翌日にリリースされたエクスプロイトでは、作者のBlasty氏が、この欠陥を利用してSUIDシェルバックドアを作成する方法を示しています。ファイルを上書きするのと同じ手法で、SUIDパーミッションを持つ、言い換えればスーパーユーザーとして実行可能な実行ファイルを上書きしています。このエクスプロイトでは、コマンドをシェルで上書きし、それを実行して/tmpにSUIDシェルを作成し、元の実行ファイルを何事もなかったかのように置き換えます。
攻撃者は、そのSUIDシェルを実行してrootに特権昇格させ、システムを完全に制御することができます。
以下は、このエクスプロイトを実行したときのスクリーンショットです。まず、find /usr/sbin -perm /4000を使用して、上書きするSUID設定プログラムを見つけます。/usr/sbin/mount.nfsは簡単にターゲットになりそうです! 次に、エクスプロイトに魔法をかけ、完全制御のrootとしてバックドアに侵入させます。
CVE-2022-0847 root mount.nfs
Sysdigシステムコールトレースツールを使用すると、sliceが呼び出された瞬間(3248)、シェルがmount.nfsに上書きされた瞬間(3250)、そしてバックドアを作成するために呼び出された瞬間(3268)を確認することができます。
CVE-2022-0847 Sysdigシステムコールトレース
このエクスプロイトを実行すると、バックドアを作成を検出するFalcoルールがトリガーされます。ルール「Set Setuid or Setgid bit」は、mount.nfsからバックドアシェルに設定されているSUIDパーミッションを検出しました。以下は、そのルール定義のコピーです。
- rule: Set Setuid or Setgid bit
desc: >
When the setuid or setgid bits are set for an application,
this means that the application will run with the privileges of the owning user or group respectively.
Detect setuid or setgid bits set via chmod
condition: >
consider_all_chmods and chmod and (evt.arg.mode contains "S_ISUID" or evt.arg.mode contains "S_ISGID")
and not proc.name in (user_known_chmod_applications)
and not user_known_set_setuid_or_setgid_bit_conditions
enabled: false
output: >
Setuid or setgid bit is set via chmod (fd=%evt.arg.fd filename=%evt.arg.filename mode=%evt.arg.mode user=%user.name user_loginuid=%user.loginuid process=%proc.name
command=%proc.cmdline container_id=%container.id container_name=%container.name image=%container.image.repository:%container.image.tag)
Priority: NOTICE
tags: [process, mitre_persistence]
Sysdig Secureのイベントログで、このアラートがどのようなものであったかを以下に示します。
CVE-2022-0847 Sysdig の脆弱性
このブログで取り上げていない他のテクニックを使えば、攻撃者は新しい力を使ってコンテナ環境から抜け出し、システム全体とそのコンテナを制御できる可能性があるのです。
これは、データの窃盗や脅迫、クリプトマイニングを実行するためのリソースの窃盗、ローカルまたはリモートネットワーク内の他のシステムに対するさらなる攻撃の開始などにつながる可能性があります。
定着させる
このエクスプロイトのもう1つの楽しい使い方は、システムとコンテナに永続的な足場を築くことです。そう、コンテナもです。私たちが攻撃者で、あるサービスを悪用してシェルを手に入れたとしましょう。そして、幸運にもシステムにnetcatがすでにインストールされているとします。netcatを使ってリバースシェルを作成することができます。リバースシェルとは、侵害されたシステムが攻撃者のシステムにアウトバウンド接続し、rootまたは他のユーザーとして攻撃者にシェルを提供することです。スクリプト言語やBash、デバイスのネットワークパイプなど、もっと簡単な方法もあるでしょうが、このデモではnetcatにこだわってみます。
リブート後の永続性を確立するために、シェルを開くようにシステムを騙す必要があります。Cron は、システムが起動した後、あるいはシェルプロセスが強制終了された場合に、シェルを作成させる信頼性の高い方法である。Kellermannのオリジナルエクスプロイト(“/tmp/dirtypipe”)を使用して、システムのcronスケジュールファイルを上書きすることができます。このエクスプロイトの仕組みにより、バイト0から開始したり、ファイルを大きくしたりすることはできません。しかし、分単位の設定の後など、ファイルの数バイトから始めて、最初の行を上書きし、ハッシュで終了して、上書きしなかった行をすべて消去することができます。
CVE-2022-0847 システムのcronを上書きする
ご覧の通り、書き込み権限のないファイルを上書きすることができました。もしすべてが計画通りに進めば、毎時30分過ぎにリバースシェルが攻撃者を取り込むために手を伸ばすのを見ることができるはずです。
これらのコマンドはすべて、MongoDBのテストに使用していたコンテナで実行されました。Kubernetesポッドとデプロイが吹き飛ばされ、再作成されたときに何が起こるか見てみましょう。設定ファイルから削除して再作成し、ポッドで直接シェルを開いて上書きされたcronファイルを確認してみます。
通常、ポッドを再作成すると、変更があっても元のイメージに戻ります。ところが…
CVE-2022-0847 MongoDBハックパーシスタンス
ご覧の通り、この脆弱性により、Dockerイメージ自体を編集し、類似のコンテナや将来のインスタンス内で永続性を確立することができました。
すべての詰まり
MITREによる公式なスコアはありませんが、CVE-2022-0847のCVSSv3.1ベーススコアは、AV:L/AC:L/PR:L/UI:N/S:C/H/I:H/Aとベクトルが極めて高く8.8と推定されます。スコアは、コンテナのイメージを内部から変更できるため、「Changed」と表示されます。ローカルのみですが、この脆弱性は、確実に悪用することが容易であり、システムの完全な侵害につながる可能性があります。
Linux ユーザーは、できるだけ早く Linux カーネルの最新バージョンにアップグレードすることをお勧めします。
CVE-2022-0847 を回避する方法
この脆弱性に対する最善の対策は、Linux Kernelを最新バージョンにアップグレードすることです。現在、Linux 5.10.102, 5.15.25, 5.16.11 と最新のAndroidカーネルで修正されています。パッチ管理を支援するために、Sysdigのファイルスキャナは、脆弱性があり、アップデートが切実に必要なシステムを特定することができます。
スクリーンショットで強調されているように、Sysdig Secureは、システムがCVE-2022-0847に対して脆弱であることを管理者に通知することができます。
CVE-2022-0847 Sysdig 検出機能
Sysdig Secureは、コンテナ上のアクティビティの変化を検出するイメージプロファイリング機能も提供しています。コンテナがどのように動作しているか、開いているファイルや実行しているプログラムを自動的に学習します。学習が完了すると、サービスの侵害、ファイルの上書き、リバースシェルなどの異常な動作を示すコンテナに警告を発し、強制終了させるルールを作成することができます。
CVE-2022-0847の詳細 Sysdig Secureによる検出
まとめ
幸いなことに、”Dirty Pipe” CVE-2022-0847” は責任を持って発見・公開され、世界中の Linux システム所有者に保護される機会を与えてくれました。これまで見てきたように、この脆弱性は、攻撃者がシステム上のあらゆるファイルを上書きし、システムやコンテナに永続的に存在する特権を昇格させることができるものです。世界中の Linux ユーザは、自分のシステムを常に最新の状態に保つ必要があります。
Sysdigは、侵害の指標を検出し、Linuxの脆弱なバージョンを検出し、イメージプロファイルがコンテナ内の異常な活動を検出できるFalcoルールへのビューを提供します。