「Meltdown」および「Spectre」を狙う攻撃の検出手法を検証

CPU の重大な脆弱性「Meltdown」および「Spectre」を利用した実際の攻撃はまだ確認されていません。しかし、「Proof of Concept(概念実証、PoC)」が公開されており、これらの脆弱性を狙う攻撃の実験によるものと推測される不審なファイルの検出も報告されています。このような状況を踏まえると、問題の脆弱性を利用した攻撃が確認されるのも時間の問題と言ってよいでしょう。Meltdown および Spectre の影響範囲は広く、1995 年以降に作成された PC が影響を受けると言われています。また、この2月にはそれまで認識されていた以外の攻撃方法も確認され「MeltdownPrime」および「SpectrePrime」と命名されるなど、攻撃危険性が高まっています。侵入した環境でメモリ上のデータへの不正アクセスを可能とするこれらの脆弱性は重要情報の窃取を目的とした攻撃で使用される可能性が高く、ヨーロッパ連合(EU)が個人情報の保護を目的として制定した「一般データ保護規則(General Data Protection Regulation、GDPR)」の対象企業にとっては特に頭の痛い問題となり得ます。

更新プログラムの適用の他にも、特に Meltdown や Spectre のように広範な脆弱性に対しては、より積極的な検出および対処を行うことが重要です。

Meltdown および Spectre は、命令の投機的実行により CPU の待機時間を減らし効率化を図る現代の CPU の設計に起因する脆弱性です。トレンドマイクロは、Intel 製プロセッサで利用可能なパフォーマンスカウンタを用い、Meltdown および Spectre を狙う攻撃を検出する手法の検証に取り組んできました。これは、アプリケーションが要求したデータがキャッシュメモリ内に見つからない「キャッシュミス」を測定することで、Meltdown および Spectre を利用した攻撃を検出する手法です。特に更新プログラムの適用によって安定性や性能の問題が発生する環境では、更新プログラムの代替策として利用可能です。

今回解説する手法は、キャッシュを利用した「サイドチャネル攻撃」に基づいた検出手法です。測定時のパラメータは異なる場合がありますが、Meltdown および Spectre を狙う攻撃で主に利用されるサイドチャネル攻撃手法「Flush + Reload」と、「MeltdownPrime」および「SpectrePrime」で利用される手法「Prime + Probe」の両方を検出することが可能です。Linux で利用可能な手法ですが、Mac では検証していません。

Spectre を狙う攻撃手法として「Spectre SGX(SgxPectre)」も報告されています。この攻撃は Intel の 「Software Guard Extensions(SGX)」機能によって作成された保護領域から情報を窃取することが可能です。SGX の公式リファレンス「SGX Programming Reference」によると、SGXの保護領域内部ではパフォーマンスカウンタが動作しない場合があります。しかし、キャッシュミスとキャッシュヒットのタイミングの違いを利用するこの攻撃は、保護領域外の信頼できないコードによって実行されるため、パフォーマンスカウンタにはキャッシュヒットとキャッシュミスの情報が含まれます。そのため、本記事の手法による検出は可能であると考えられますが、完全な検証を行ったわけではないため確証はありません。また、サンプリング周期やしきい値のような測定時のパラメータは環境によって異なります。

■Meltdown および Spectre を利用した攻撃の仕組み

Meltdown を利用した攻撃の仕組み

Meltdown は、アクセス権のないメモリ領域にアクセスする命令を投機的に実行し、キャッシュを利用したサイドチャネル攻撃によって実際の値を取得することが可能な脆弱性です。アクセス権が無いため CPU は命令の結果を破棄しますが、攻撃者は最下層のキャッシュメモリである「Last Level Cache(LLC)」に残った値を取得することが可能です。

以下はこのような攻撃で利用される命令の一例です。

mov rax, <アクセスが禁止されているメモリアドレス>

禁止されたメモリ領域へのアクセスはページフォールトを引き起こし、その結果セグメンテーション違反エラー「Segmentation Violation(SIGSEGV)」が発生します。通常このエラーはプロセスを終了させますが、攻撃者は SIGSEGV を処理するハンドラを作成し、アプリケーションを終了させずにメモリブロックを読み取ることが可能です。ただし、SIGSEGV はオペレーティング・システム(OS)内部に痕跡を残します。

SIGSEGV の痕跡は、必要に応じてスレッドをトランザクション実行する Intel 製プロセッサの機能「Transactional Synchronization Extensions(TSX)」を使用することで取り除くことが可能です。攻撃者は、トランザクション実行用の命令「Restricted Transactional Memory(RTM)」によって TSX の機能を利用します。具体的には、以下に示したように Meltdown を利用する攻撃コードを RTM の命令「xbegin」と「xend」で囲みます。こうすることで、ページフォールトによる例外シグナルを取り除き、痕跡を減らしつつより高速に Meltdown を狙う攻撃が可能になります。

xbegin

mov rax, <アクセスが禁止されているメモリアドレス>



xend

Spectre を利用した攻撃の仕組み

Spectre も投機的実行を利用しますが、Meltdown とは異なり、アクセスが禁止されたメモリを条件分岐内で読み取ります。ただし、この攻撃シナリオでは、分岐予測に基づいて投機的に実行された分岐内の命令は実際には利用されないことに留意してください。

以下は Spectre を利用する攻撃コードを簡略化したものです。



mov rax, [rbp-10] // rax の値は 5 に等しい

mov rbx, [rbp-18] // rbx の値は 4 に等しい

xor rax, rbx

je no_way



ret

no_way:

  mov rax, <アクセスが禁止されたメモリアドレス>

攻撃者の狙いは、条件分岐を左右する命令「XOR」の結果予測を間違うように CPU を「訓練」し、命令「no_way」が投機的に実行されるようにすることです。予測が外れた場合、CPU は実行結果を破棄しますが、攻撃者はキャッシュに残った値を取得することが可能です。この攻撃は CPU 内で行われるため、ページフォールトは発生しません。

Meltdown と同様に、攻撃者はキャッシュを利用したサイドチャネル攻撃によって値を取得することが可能です。また、OS に例外が渡されることもありません。ただし、Spectre を利用した攻撃は CPU の分岐予測に依存するため、Meltdown に比べて実行が困難です。

■キャッシュミスの測定による Meltdown および Spectre を利用した攻撃の検出

Meltdown を利用した攻撃ではページフォールトによる痕跡が残ります。そのため、単純にカーネルの状態を追跡することによって検出可能です。具体的には、OS 内でセグメンテーション違反(SIGSEGV)シグナルを捕捉し、あまりに多くのセグメンテーション違反シグナルを発生させているプロセスがあった場合、警告を発します。

トレンドマイクロは、Linux のイベント追跡ツール「kprobe」を使用し、カーネルがシグナルを送る際に利用する「force_sig_info」イベントを捕捉することでこの検出手法を検証しました。その結果、自作のシグナルハンドラを使用することで Meltdown を利用した攻撃の検出に成功しました。1 つのプロセスが大量の SIGSEGV シグナルを発生させるという状況はかなり限られているため、これは誤って攻撃として検出してしまう「偽陽性」の少ない手法です。しかし、TSX 命令を利用している場合、SIGSEGV は OS に渡されないためこの検出方法は無効です。

Meltdown および Spectre を狙う攻撃は、CPU のマイクロアーキテクチャの設計によって可能になる攻撃で、どちらもキャッシュを利用したサイドチャネル攻撃によって実際の値を取得します。このようなサイドチャネル攻撃は、パフォーマンスカウンタを利用することにより検出可能です。

キャッシュはメモリからデータを読み込む際の遅延を減らすための仕組みです。現代の CPU のキャッシュ構造は、最も高速な L1 キャッシュから最も低速な L3 キャッシュまで、複数の層に分かれています。キャッシュに含まれるデータには「Li⊂Li+1」のような包含関係があります。また、コア間で共有される L3 キャッシュにはデータと命令の両方が含まれるため、L3 キャッシュは攻撃を受けやすいキャッシュでもあります。CPU から見て「Dynamic Random Access Memory(DRAM)」の手前に位置する L3 キャッシュには DRAM のマッピング情報も含まれています。

現代の CPU の構造

図 1:現代の CPU の構造

メモリから値を取得する際、その値がキャッシュに存在する場合(キャッシュヒット)は、DRAM から値を取得する場合(キャッシュミス)に比べてはるかに高速なアクセスが可能です。そのため、攻撃者はアクセスにかかった時間からキャッシュヒットとキャッシュミスを区別することができます。これが キャッシュを利用したサイドチャネル攻撃によって情報を取得する仕組みです。攻撃の際、理論上キャッシュミスが増加します。そのため、キャッシュミスを計測することにより攻撃の検出が可能ですが、偽陽性を避けるために不正な挙動と正常な挙動を区別する必要があります。

キャッシュミスは、「パフォーマンス・カウンタ・モニタ(Performance Counter Monitor、PCM)」を利用することで計測可能です。「Core Solo」および「Core Duo」以降の Intel 製プロセッサには 2 種類の PCM が導入されており、1 つはマイクロアーキテクチャに基づく PCM で、もう1つはモデルに基づく PCM です。

アーキテクチャに基づく PCM で利用可能なカウンタは「CPUID 命令(パラメータ:eax=0x7, ecx=0x0)」を実行することで確認可能です。CPUID 命令を実行するツールを利用してアーキテクチャ情報を確認したところ、以下の結果が得られました。

Printing architectural CPU Information:

Version ID of architectural performance monitoring = 4

Number of general-purpose performance monitoring counter per logical processor = 4

Bit width of general-purpose, performance monitoring counter = 48

Length of EBX bit vector to enumerate architectural performance monitoring events = 7

Core cycle event available: yes

Instruction retired event available: yes

Reference cycles event available: yes

Last-level cache reference event available: yes

Last-level cache misses event available: yes

Branch instruction retired event available: yes

Branch mispredict retired event available: yes

Number of fixed-function performance counters ((if Version ID > 1) = 3

Bit width of fixed-function performance counters (if Version ID > 1) = 48

上記の中で LLC に関連したカウンタは、「LLC References」と「LLC Misses」です。Intel による定義は以下の通りです。

  • 「Last Level Cache References」(Event Select:0x2E、Umask:0x4F)

    CPU コアが Last Level Cache内のキャッシュラインを参照するリクエストの回数
  • 「Last Level Cache Misses」(Event Select:0x2E、Umask:0x41)

    Last Level Cache参照時のキャッシュミスの回数

キャッシュミスを測定するために、特に仮想環境では、PCM が利用可能であることを確認する必要があります。カウンタの値を読み取る命令は「usermode」からは実行できないため、CPU とカーネルが値の読み取りに対応している必要があります。また、カーネルから値を取得するためのアプリケーションも必要です。

パフォーマンス・カウンタ・モニタ(PCM)の利用に必要な条件

図 2:パフォーマンス・カウンタ・モニタ(PCM)の利用に必要な条件

Linux 環境では性能分析ツール「perf」によってカウンタの値を取得することが可能です。その他の環境では、環境に応じたツールを利用してください。

測定可能なイベント一覧は「perf list」コマンドで確認します。LLC References LLC Misses にはそれぞれ「cache-references」と「cache-misses」という別名が付けられています。Intel 製プロセッサの場合、「perf stat -e r4f2e,r412e」コマンドによって直接カウンタの値を読み取ることも可能です。

LLC に関連したカウンタの値には「LLC-loads」と「LLC-load-misses」もあり、攻撃の検出に利用可能です。しかし、これらのカウンタはモデルに特有なため、環境によっては利用できない場合があります。例えば、「Sandy Bridge」マイクロアーキテクチャを実行する物理マシンでは LLC-load-misses は利用できませんでしたが、LLC-loadsは取得可能でした。

マイクロアーキテクチャが対応していないカウンタ

図 3:マイクロアーキテクチャが対応していないカウンタ

これらのカウンタは仮想化ソフトウェア「VMware」で「Virtual CPU Performance Monitoring Counters」を有効にして実行した仮想マシンでも取得できませんでしたが、LLC References と LLC misses は取得可能でした。

LLC References と LLC Missesは仮想マシンでも取得可能

図 4:LLC References と LLC Missesは仮想マシンでも取得可能

攻撃の検出に利用する前に、「perf stat」コマンドを実行して各カウンタの対応状況を確認してください。今回の検証では、LLC References、LLC Misses、LLC-loads、LLC-load-misses の中から各環境で利用可能なカウンタを使用しました。また、人気のあるクラウドサービスが提供する Linux 仮想マシンでもこれらのカウンタが利用可能か確認しましたが、利用不可あるいは非対応でした。

■検出テスト

テスト手法

キャッシュミスを利用することで実際にサイドチャネル攻撃を検出することが可能であることを検証するために、以下の設定で LLC に関連したパフォーマンスカウンタを測定しました。

  • 各論理 CPU のすべてのプロセスまたはスレッドについて LLC References と LLC Misses を測定し、サンプリング周期として設定した回数のイベントが発生するごとにカウンタの値を取得する。LLC Misses が発生する割合は以下の式によって計算する。

  • MR > 0.99 の場合に検出とする。
  • 2 通りのサンプリング周期(P1=10,000、 P2=20,000)で検証を行う。

検証シナリオは以下の通りです。

  1. 負荷テストのためのコマンド「stress」を各 2 分間実行(# には論理 CPU の数を指定)
    1. stress -c #
    2. stress -i #
    3. stress -m #
    4. stress -d #
    5. stress -c #
    6. stress -c # -i # -d #
    7. stress -c # -i # -d # -m #
  2. 動画再生ソフトウェア「VLC プレイヤー」による 4K 動画の再生
  3. Meltdown の PoC を実行
  4. Spectre の PoC を実行

テストに使用した環境は以下の通りです。

  • 物理マシン 1:Core i5-2430M @2.40GHz、Sandy Bridge、Ubuntu 14.04
  • 物理マシン 2:Core i7-4600U @2.10GHz、Haswell、Ubuntu 14.04
  • 仮想マシン 1:VMware ESX VM を Intel Xeon E5-2660 @2.2GHz、Sandy Bridge、 Ubuntu 16.04 上で実行、vPCM.enable = “TRUE”、vPCM.freezeMode = “vcpu”

上述のシナリオを実行し、以下の結果を得ました。

物理マシン 1

サンプリング周期 P1=10,000

  • Stress コマンド実行時は、メモリの確保と解放を行う「-m」オプションを指定した場合にのみ偽陽性(FP)が発生
  • 4K 動画の再生により FP が発生
  • Meltdown のPoCの検出に成功
  • Spectre のPoC の検出に成功

サンプリング周期 P2=20,000

  • Stress コマンド実行時は「-m」オプションを指定した場合にのみ FP が発生
  • 4K 動画の再生による FP の発生無し
  • Meltdown の PoC の検出に成功
  • Spectre の PoC の検出に成功

PCM を用いた Spectreの PoC の検出例

図 5:PCM を用いた Spectreの PoC の検出例

物理マシン 2

サンプリング周期 P1=10,000

  • Stress コマンド実行時は「-m」オプションを指定した場合にのみ FP が発生
  • 4K 動画の再生により FP が発生
  • Meltdown の PoC の検出に成功
  • Spectre の PoC の検出に成功

サンプリング周期 P2=20,000

  • Stress コマンド実行時は「-m」オプションを指定した場合にのみ FP が発生
  • 4K 動画の再生による FP の発生無し
  • Meltdown の PoC の検出に成功
  • Spectre の PoC の検出に成功

仮想マシン 1

サンプリング周期 P1=10,000

  • Stress コマンド実行時は「-m」オプションを指定した場合にのみ FP が発生
  • N/A
  • Meltdown の PoC の検出に成功
  • Spectre の PoC の検出に成功

サンプリング周期 P2=20,000

  • Stress コマンド実行時は「-m」オプションを指定した場合にのみ FP が発生
  • N/A
  • Meltdown の PoC の検出に成功
  • Spectre の PoC の検出に失敗

LLC-loads と LLC-load-misses イベントの測定による検証結果は以下の通りです。

物理マシン 1

当該カウンタの利用不可

物理マシン 2

サンプリング周期 P1=10,000

  • Stress コマンド実行時は「-m」オプションを指定した場合にのみ FP が発生
  • 4K 動画の再生による FP の発生無し
  • Meltdown のPoCの検出に成功
  • Spectre のPoCの検出に成功

サンプリング周期 P2=20,000

  • Stress コマンド実行時は「-m」オプションを指定した場合にのみ FP が発生
  • 4K 動画の再生による FP の発生無し
  • Meltdown の PoC の検出に成功
  • Spectre の PoC の検出に成功

仮想マシン 1

当該カウンタの利用不可

■サンプリング周期と偽陽性(FP)の関係

テスト結果からサンプリング周期が FP の発生に影響することが判明しました。また、「stress -m」コマンド実行中にも FP が発生しました。「-m」オプションの仕様は以下の通りで、N 個の CPU がメモリの確保と解放を繰り返します。

-m, –vm N

  spawn N workers spinning on malloc()/free()

LLC は物理メモリと関係があるため、FP の発生も理解できます。そのため、メモリ確保が頻繁に発生するような環境でこの検出手法を利用する場合はより慎重になる必要があります。

今回の検証結果によると、より正確に攻撃を検出することのできるカウンタは LLC-loads と LLC-load-misses でした。しかし、LLC references(cache-references)と LLC misses(cache-misses)も利用可能です。

検出手法 例外の発生を回避する手法 検出 偽陽性 仮想環境への攻撃可否
PCM TSX 可能 多い TSX が利用可能な場合可能

(今回の検証では利用不可能)
ktrace TSX 不可能 N/A TSX が利用可能な場合可能

(今回の検証では利用不可能)
PCM 条件分岐 可能 多い 可能
ktrace 条件分岐 不可能 N/A 可能
PCM 無し

(メモリに直接アクセス)
可能 多い 可能
ktrace 無し

(メモリに直接アクセス)
可能 少ない 可能

表 1:カーネルトレーシングツール「ktrace」 と PCM を用いたテスト結果一覧
サイドチャンネル攻撃の手法は「Flush + Reload」
注:例外の発生を避けるために「条件分岐」を利用するタイプの PoC では Ktrace による検出はできません。

■環境に応じた検出手法の使い分けと調整が必要

カーネルで SIGSEV シグナルを追跡する手法は、TSX-NI 機能が利用できない環境に限って Meltdown を利用する攻撃を検出することが可能です。TSX は、Haswell マイクロアーキテクチャに基づく Intel 製マイクロプロセッサのような CPU で利用可能です。

CPU の PCM が利用可能な場合、キャッシュを利用したサイドチャネル攻撃を検出することが可能です。この手法が利用可能かどうかは、perf がインストールされた Linux 環境で「perf stat -e -a cache-references,cache-misses,LLC-loads,LLC-load-misses」コマンドを実行することで確認できます。ハードウェアの PCM は、Amazon AWS、Azure、Virtual Box のようなほとんどの仮想環境では初期設定で利用不可能です。しかし、VMware では有効化することが可能です。

Windows や macOS のようなその他の環境では usermode からは PCM にアクセスできません。これらの環境では、カウンタの値やキャッシュミスの増加に寄与しているプロセス ID(PID)を取得するために適切なカーネルドライバが必要です。

また、実行環境に応じて検出パラメータを調整することも推奨されます。サンプリング周期を大きく取ると FP は少なくなりますが、ある程度の休止時間を置きながら小さな領域のメモリを対象に攻撃が実行された場合、それを見逃してしまう恐れがあります。ただし、その場合攻撃に必要な時間は増加します。逆に、より大きなメモリ領域を連続で読み取るような攻撃は検出が容易になります。一方、サンプリング周期を小さく取ると FP は増加します。今回の検証では、物理マシンよりも VMware の方が、サンプリング周期が FP に与える影響が小さいことが確認できました。他にも、各ユーザが使用しているアプリケーションに基づいて判定基準を調整することも重要です。また、不審な PID(プロセス ID)と TID(スレッド ID)をユーザに伝えることで必要な措置を取るように促すことも可能です。

以上をまとめると、ハードウェアの PCM によって、FLUSH+RELOAD 手法を利用したキャッシュサイド攻撃を検出することが可能ですが、実行環境に応じて精度を検証し、パラメータを調整して FP を減らす必要があるということです。

環境によって利用可能な機能が異なるため、Meltdown および Spectre を利用した攻撃を検出する万能の手法はありません。徹底した防御は、変化を続ける脅威に注意を払い積極的に検出することと同様に重要です。特に Meltdown や Spectre のような影響範囲の広い脆弱性を利用する攻撃に対しては、攻撃チェーンを把握して適切に対処する積極的なインシデント対応が求められます。

参考記事:

翻訳: 澤山 高士(Core Technology Marketing, TrendLabs)