Google の Project Zero が Samsung の Knox Hypervisor をバイパスする方法を発見 (1 月のパッチで修正)

最新の Project Zero ブログ投稿で、チームは、Knox Hypervisor と呼ばれる、Samsung のリアルタイム カーネル保護をバイパスする方法を発見しました。

Google の Project Zero チームは、安全だと思われる Samsung Knox セキュリティ スイートを実行している Samsung の携帯電話を攻撃できるようにする多数のエクスプロイトを確認しました。 このブログでは、すべての脆弱性は Samsung に引き継がれ、Samsung が実際に 1 月のソフトウェア アップデートで修正をリリースしたと述べています。


背景

Samsung が導入した Samsung Knox セキュリティ ソフトウェア スイートの一部として、Android アプリケーションとカーネルの間に位置する、 ハイパーバイザー. これは、Android デバイスをさらに安全にするための追加レイヤーとして使用できます。 Samsung Knox ハイパーバイザーは「」と呼ばれます。リアルタイムのカーネル保護" または略して RKP (この記事の残りの部分で参照します)。

カーネルは Android ソフトウェア スタックの RKP の下に位置し、デバイス上で実行されるアプリケーションは最上位に位置します。 RKP の背後にある考え方は、デバイスによって行われるすべてのリクエスト (メモリおよびその他のリソース) として、デバイスに追加のセキュリティ層を提供することです。 カーネルへのアプリケーションは、最初に Knox を経由する必要があります。Knox は、アプリケーションが何かを行っているかどうかを検出しようとします。 そうすべきではありません。 RKP は、アプリケーションがデバイスを侵害するために使用する可能性のある機密情報を隠すための追加レイヤーによる隠蔽によるセキュリティも提供します。

このブログの投稿では、Android のメモリ、RKP、およびオペレーティング システムが一般的にどのように機能するかについて非常に詳しく説明されているため、発見された内容の概要を簡単に説明できるように要約して簡略化しました。 ただし、非常に啓発的な内容なので、時間があれば全文を読むことをお勧めします。


悪用 #1:

カスラー または、カーネル アドレス空間レイアウトのランダム化は、ブート時にメモリ内のカーネル コードの位置をランダムな量だけ変更するプロセスです。 デバイスが起動されるたびに、カーネルは異なるアドレス空間 (メモリ内の領域) にロードされます。 このアイデアは、起動するたびにカーネル コードがメモリ内でランダムな量だけ「移動」するため、カーネル コードを攻撃するためにカーネル コードがどこにあるかを見つけるのを難しくすることです。 これは攻撃者を防ぐための素晴らしいステップのように思えますが、最近では

研究 KASLR はローカル攻撃者に対して堅牢な方法で実装するのが実際には非常に難しいため、ソフトウェアのバグや脆弱性を必要とせずに実際にこれを破ることができることを示しました。

RKP ソフトウェアの場合、KASLR をバイパスする機能は、実際には上記で参照した調査よりも簡単です。 すべての Android デバイスのメモリは、Android デバイスが印刷または出力するとき (画面への出力かどうかにかかわらず)、デバイスを攻撃から保護するためにポインタによって参照されます。 ログまたはデバッグ用にファイルに保存されます)、ポインタ参照は匿名化されるため、ファイルを読み取るときにポインタが実際にどこを指しているかを見つけることができなくなります。 出力。

記憶ポインタは場所を示す道路標識のようなものであり、匿名化はそれを曖昧にすることだと考えてください。 テレビと同様に、匿名化は撮影後に行われ、Android も匿名化が正しく設定されている場合にのみ、出力時にこの匿名化を適用します。 [彼] が遭遇したすべてのデバイスにはポインタ匿名化が正しく設定されている. これを破るのは非常に難しいように聞こえるかもしれませんが、必要なのは、匿名化されていない (ぼかされている) 単一のポインタ (道路標識を想像してください) を見つけることだけです。 ポインターがログまたは他の場所に書き込まれるとき、カーネル開発者 (これは平均的な Android アプリ開発者ではないことに注意してください) によって行われます。 画面または ファイル。

したがって、匿名化されていないポインターを見つけることができれば、カーネルのランダム アドレス シフトを 2 つの差として計算できます。 興味深いことに、作成者はカーネル内で悪用可能なポインタを見つけることができませんでしたが、RPK 内でそれを見つけました。 開発者がデバッグ (ログ) 出力内のポインタを匿名化するのを忘れた場合、これは 打ち間違え。 Android でポインタを匿名化するには特別なコードを使用する必要がありますが、RPK 開発者が誤ってコードを使用したことが判明しました。 小文字の「k」 の代わりに 大文字の「K」. したがって、カーネル コードのランダム シフト量を把握して攻撃することは比較的簡単でした。


悪用 #2:

次のエクスプロイトはもう少し複雑です。Samsung Knox は、一連のルールをデバイスのメモリに適用して悪意のあるコードを阻止することでデバイスを保護します。 ルールは次のとおりです。

  1. カーネルのコードを除くすべてのページ (メモリ内のコード) は、「特権実行なし」としてマークされます (ここにあるコードは決して実行できないことを意味します)。
  2. カーネル データ ページ (メモリ内のプログラムによって使用されるデータ) が実行可能としてマークされることはありません (したがって、ここにあるコードは決して実行できません)
  3. カーネル コード ページ (メモリ内のコード) は書き込み可能としてマークされることはありません (したがって、悪意のあるコードが変更することはできません)。
  4. すべてのカーネル ページは、ステージ 2 変換テーブル (アプリケーションが実際のメモリの場所を知ることをさらに防ぐために、アプリケーションとカーネルの間にあるテーブル) で読み取り専用としてマークされます。
  5. すべてのメモリ変換エントリは、アプリケーションに対して読み取り専用としてマークされます。

作成者が上記のルールの実装に関して問題を発見した場所であるため、ルール 3 に焦点を当てます。 実際、RPK はカーネルのメモリを読み取り専用としてマークしますが、KASL の見落としとしてホールが発見され、それが原因で 「読み取り専用」と思われるセクションにコードを書き込む. ブート時にカーネルの場所を難読化するために、メモリがカーネルに割り当てられますが、このメモリ量はカーネルのテキスト セグメントよりもはるかに大きくなります。 より多くのメモリを割り当てると、どこにでもある可能性がある実際のカーネル コードを見つけることがはるかに困難になり、上で見たように、デバイスの起動ごとにカーネル コードがランダムに移動されます。

_text と _etext は保護範囲をマークします

著者は、カーネルによって使用されているメモリが確かに「読み取り専用」としてマークされていることを確認できましたが、カーネルを隠すために使用されていた大量のメモリの残りの部分は、 ない 「読み取り専用」としてマークされています。 これは、RKP が KASLR スライドの適用後にカーネルのテキストを含む領域のみを保護するためです。


悪用 #3

3 番目のエクスプロイトでは、作成者は読み取り専用に制限されるべきメモリの別の領域にもアクセスできました。 RKP はメモリを保護し、 ハイパーバイザー構成レジスタ (HCR) を使用して主要なカーネル操作を制御します。 HCR のポイントは、有効で実際のカーネル操作がレジスタにアクセスし、悪意のある攻撃をブロックできるようにすることです。 これは、仮想化機能を制御するレジスタへの呼び出しをチェックすることによって行われます。 HCR は、通常は処理される特定の操作をブロックするように構成されており、RKP はリクエストを許可するか拒否するかを選択できます。

このエクスプロイトでは、HCR コントロールは 2 つのレジスタをカバーしていない それは非常に重要であることがわかりました。 著者は ARM リファレンス マニュアルを詳しく調べ、最初のレジスタによって基本的にアプリケーションの RKP をオフにできることを発見しました。 」EL1 用システム制御レジスタ (SCTLR_EL1) は、メモリ システムを含むシステムのトップレベルの制御を提供します完璧な世界では、アプリケーションは RKP を介してマップされたメモリを使用し、アプリケーションがアクセスできるものを RKP が制御できるようになります。 ただし、このレジスタをオフにすると、 RKP を無効にする これは、デバイスを RKP がインストールされる前の動作状態に効果的に戻すことにより、RKP によって提供される追加のセキュリティなしでデバイスが物理メモリにマップされることを意味します。 これは、作成者が、RKP ソフトウェアによって元々正しくブロックされていたメモリに対して読み書きできることを意味します。

見逃された 2 番目のレジスタには、より微妙な影響がありましたが、最終的にはセキュリティに同様に壊滅的な影響を与えました。 の EL1 の変換制御レジスタ (TCR_EL1) レジスタは、アプリケーションが動作するページと呼ばれるメモリの量に直接関係します。 AARCH64 Linux カーネル (Android など) は 4KB の変換サイズを使用するため、RKP は 4kb のページ サイズにハードコードされています。 問題のレジスタ (TCR_EL1) は、返されるメモリのサイズに ARM チップセットを設定します。 判明したのは、 このレジスタは HCR によって保護されていません したがって、作成者がページ サイズを 64 kb に変更したように、攻撃者もそれを変更することができます。

これが意味するのは、リクエストが RKP によって実行されるとき、アクセス可能な実際のメモリ量は 4 kb ではなく 64 kb になるということです。 その理由は、ARM チップセットが依然としてページ サイズを制御しており、エクスプロイトによって 64 kb に設定されているためです。 RKP はエクスプロイト #2 にリストされているルールの一部としてメモリへの書き込みを保護するため、メモリは実際には保護されたままです。 しかし、ここに落とし穴があります。RKP は 4kb にハードコーディングされているため、レジスタが更新されても 64kb のページ サイズに変更されません。 メモリの最初の 4kb のみが保護されます 攻撃者に実行を許可する 残りの 60kb で何でもできる.


悪用 #4

著者が示した最後のエクスプロイトは、RKP ソフトウェアが存在するメモリを参照しているため、攻撃者は RKP ソフトウェア自体を攻撃する可能性があります。 Linux カーネルでも使用されるこの種の攻撃を阻止する 1 つの方法は、プログラムを仮想メモリ アドレス空間からマップ解除して、アプリケーションがプログラムを参照できないため攻撃できないようにすることです。

メモリとは、物理メモリを仮想メモリにマップするポインタとテーブルがすべてであることを思い出してください。 このタイプの攻撃における通常の防御に従って、RKP は攻撃されないように自身のマップを解除します。 ただし、カーネルがそのような機能を提供しない場合、RKP ではメモリの一部をマップして読み取り/書き込みとしてマークすることができます。 唯一のチェックは、マッピングが要求されているアドレスがメモリ内で RKP 自体が存在する領域であるかどうかを確認するチェックを RKP が行わないため、それが基礎となるカーネル自体ではないことです。 基本的にはRKP 自分自身を再マッピングできるようにする アプリケーションがアクセスできるアドレス空間に戻り、副次的に影響を与えます。 メモリは自動的に読み取り/書き込みとしてマークされます そのため、攻撃者はメモリを好きなように使用できるようになります。


結論

上記の 4 つのエクスプロイトに関する最大の問題の 1 つは、ベースの Android カーネルに機能が欠如しているため、これらのエクスプロイトを実行するのがどれほど難しいかについて著者が言及していることです。 皮肉なことに、安全な RKP ハイパーバイザーは、攻撃を実行するために必要なすべてのツールを提供していました。 善意のソフトウェアが、解決するよりも多くの問題を引き起こしてしまう場合があることを示しています。私たちは人材がいるのが幸運です。 Gal Beniamini のように、自らの手を汚して、ドキュメントが実際のソフトウェアと一致するかテストすることをいといません。 そうです。

これらのエクスプロイトは恐ろしいように見え、Knox が非常に脆弱であるように見えますが、これらの問題はすべて解決済みであることを皆さんに安心していただきたいと思います。 1月のアップデートで修正されました サムスンから。 さらに、これらのエクスプロイトには ARM プロセッサとプログラミングについての非常に深い理解が必要であるため、これらのエクスプロイトを使用する際の参入障壁は天文学的に高くなります。


出典: プロジェクトゼロ