このブログは「風見鶏」が、日々気づいたこと、思ったこと、したことを気ままに綴る日記です。2008年9月に旧ブログから引っ越しました。バックアップをご覧ください。

ゲストログインがうまくできないので、コメントを承認制にしました。スパムでないことを確認の上、公開します。判断はあくまで「風見鶏」の主観で行いますので、文句は受け付けません。(笑)承認が遅れることもままあると思いますが、あしからず・・・

システムトラブルのため、2015年以降のブログ画像と2018年5月以降の記事が消失しました。画像は鋭意、新しい物から順次復旧中ですが記事については残念ながら戻せません。残念ですが、あきらめます。

なお、ここに書いていることは、あくまで個人的な思いであり、いかなる組織をも代表、代弁するものではありませんし、無関係ですので念のため。

そろそろ始動、そしてまた歳を食う

| コメント(0) | トラックバック(0)

昨日の朝、実家を離れて自宅に向かう。ルートはいつもの高山経由。平湯から松本に抜けるルートである。

午後2時半頃に諏訪湖SAで遅めの昼飯。ちょっと腹が減っていたので大盛りチャーシュー麺などを食ってしまい、その後ちょっと胃にもたれてしまう。

ここで、ちょっと車の足回りに不具合を発見。以降、スピードを落として左車線をEyeSight任せで走る。それはそれで楽でいいのだが、ちょっと眠くなってしまうのが難点である。とりあえず、双葉SAでちょっと小休止がてら富士を眺める。

途中軽い渋滞があったものの、比較的順調に流れて、午後6時前には自宅に帰り着いた。ちょっと疲れたので、軽く晩飯と一杯引っかけて、あとはだらだら過ごして、そのまま就寝。今朝はちょっと寝坊して8時起き。それから、久しぶりに自宅周辺の朝の散歩に出かける。気温は5℃台と、この時期としてはちょっと高め。歩いていてもそれほど寒くは感じない。まぁ、実家あたりの寒風に比べればずいぶんマシである。

やはり、平地の実家周辺と違い、自宅周辺はアップダウンがあってメリハリがつくのがいい。景色が変わるのも退屈しなくていい感じだ。

見慣れた景色だが、しばらくぶりである。

今日は頑張ってフルコースで歩き、公園の鉄棒で懸垂、腕立てなども・・・。とりあえず日常回帰である。

そんな感じで2時間弱歩いて、朝飯の後、ちょっと仕事・・・のつもりが、またしても、今度はSpectreの論文読みにハマってしまう。先日、Meltdownを読んだので、今度はSpectreというわけだが、ちょっと軽く・・・のつもりが、読んだ内容をまとめていたら、結局夕方になってしまった。とりあえず、まとめた内容を以下に書いておく。


Spectre攻撃は、Meltdown同様にキャッシュへの副作用を利用してサイドチャネルから情報を得る方法だが、カーネルメモリや仮想空間にマップされた実メモリページではなく、特定のプロセスの仮想空間内のデータを狙う手法である。従って、Meltdown対策としてのKAISERは有効ではない。攻撃対象となるのは、CPUが持っている分岐予測実行(投機的実行)機能。


分岐予測と分岐先予測


Meltdownの時に書いたように、最近のCPUは、ある命令の待ち時間の間に後続命令の実行準備や先行命令に依存しない命令を実行して結果を保留する、アウトオブオーダー実行の機能を持っているが、これを含めて命令コードを先読みするパイプライン機能は分岐命令によって乱されるため、分岐の多い処理ではパフォーマンスが低下する。これをカバーするために付加されたのが分岐予測の技術である。最近のCPUでは、よく使用される条件分岐命令の仮想アドレスと、その最近の分岐の履歴をテーブルとして保持していて、この情報に基づいて次に先読みすべきコードを決定している。また、間接ジャンプやリターン命令といったダイナミックに飛び先が変わる命令については、よく使用される分岐先アドレスを保持していて、これを用いて分岐先を予測し先読みを行う。分岐予測の結果を高速に利用するため、各命令の仮想アドレスは下位30ビット程度をハッシュテーブル化して保持され(BTB:Branch Target Bufferと呼ばれる)、実行時は分岐命令がデコードされているかどうかにかかわらず、先読みのために使用される。このアドレスは仮想アドレスであるため、たとえば、異なるプロセスであっても、同じ場所に分岐命令があれば(ASLRなどのため、共有ライブラリであってもこの可能性は極めて低いが)同一のものとして扱われる。


分岐予測については、外部からその分岐をコントロールできれば、あらかじめ分岐有無を学習させることが可能である。また、分岐先予測については、対象となる命令の仮想アドレス下位30ビットが等しくなる位置に同じ命令がある攻撃用プロセスを準備できれば、他のプロセスから分岐先予測を攪乱することも可能である。(論文では20ビット程度でもよかったと書かれている)


基本的な攻撃の原理


分岐を伴うコードで、予測結果によって先読みされる部分に、外部から与えたデータで任意の仮想アドレスを参照するような命令を持つ部分を探し、この分岐命令についてそのコードを先読み実行するように学習させた上で、参照したいメモリアドレスを与えて、予測を失敗させる。これにより、もし参照したメモリブロックがキャッシュされていなければキャッシュ要求が発生し、キャッシュされる。あらかじめキャッシュを削除してからサイドチャネルでキャッシュされた場所を調べる手法は、Meltdownと同様。


分岐先予測を使った攻撃ではもう少し自由度が上がる。メモリ参照を行うコードは分岐命令とは全く違う場所にあってもよい。この場合は、攻撃プロセスを使って、分岐先予測を攪乱し、メモリ参照を行うコードのアドレスをBTBに押し込んでしまえばいい。これは、バッファオーバフロー攻撃時のROP(Return Oriented Programing)と類似の手法である。もちろん、実行結果は最終的に破棄されることになるが、キャッシュは残る。


以下、具体的な攻撃コンセプトの例。


A) 条件分岐を攻撃する方法(分岐予測への攻撃)例


1) 標的とするプロセスのプログラム内で、外部から与えられる値によって分岐条件が変わり、投機的実行によって、その値に依存する位置のメモリブロックをキャッシュする副作用を発生するようなコードを見つける・・たとえば、指標値による二重のテーブルルックアップ


if (x < size_a1)
  y = a2[a1[x] * 256];

のようなコード。これは機械命令に落ちる際に if 条件を満たさなければ分岐するようなコードになるが、この分岐予測が「分岐しない」となる場合は、xによってa1 + xのメモリにある値が参照され、それに対して256(キャッシュブロックのサイズの倍数の値)を掛けた値だけa2に加えた位置へのアクセス要求が発生し、そのブロックがキャッシュされる。


2) この分岐に対して、いくつか正常な(size_a1より小さな)値を与えて学習させた後に、xに不正な(size_a1より大きな)値を与えると、分岐予測によって、不正なxを用いた計算が先行して(投機的に)行われる。たとえば、事前にキャッシュをあふれさせたりフラッシュしてしまうことで、条件評価の際にsize_a1をメモリから取得しなければいけないなどの時間がかかるようにしておく必要がある。これにより、a2 + (a1 + x) * 256 の位置のブロックがキャッシュされる。


3) サイドチャネルを使って、新たにキャッシュされたブロックのアドレスを調べると、a1 + xにある値が推定できるので、この作業をxを変えながら行うことで、標的プロセスの仮想メモリ空間内にある値を読み出すことが可能になる。


B) 間接分岐やリターン命令を攻撃する方法(分岐先予測への攻撃)例


1) 標的プロセス内で、2つのレジスタ(R1, R2)に外部から操作可能な値を持った状態で実行される間接分岐(メモリ間接のジャンプ)命令やリターン命令などを見つける。


2) 同じく標的プロセスのコードや使われている共有ライブラリ(DLL, SOなど)内で、まず、R1をオフセットとしてメモリをDWORD参照し、その値をR2に加える(32bit演算)ようなコードと、その次にR2を使ってメモリを間接参照するなんらかの命令を持つ部分を見つける。たとえば、以下のような例(実際のWindowsのコードの一部)が書かれている。ここで、EDIとEBXが外部から制御可能。edxの値は既知である前提。


adc edi,dword ptr [ebx+edx+13BE13BDh]
adc dl,byte ptr [edi]

3) 1)の間接分岐もしくはリターン命令について分岐先予測ロジックを攻撃し、2) のコードを分岐先と予測するように学習させる。


4) R1を参照したいアドレス(CPUによってバイトオーダーを考える必要あり)にし、R2をメモリ参照によってアクセスされるアドレスの先頭に設定するような値を標的プロセスに外部から与えて 1)のコードを実行させる。これにより、間接分岐やリターン命令がメモリアクセスを待っている間に分岐先予測によって2)が投機的に実行され R2 + [R1]<<24 + [R1+1]<<16 + [R1+2] << 8 + [R1+3} の位置のメモリ(バイトオーダーに注意)がキャッシュされる。


5) サイドチャネルを使用して新たにキャッシュされたブロックのアドレスを調べることで、4)のアドレスがわかる。A)ほど単純ではないが、こうした手法をR1の値を変えながら繰り返せば(メモリアクセスバウンダリーの問題は考慮が必要だが)標的プロセスの任意のメモリの値を取得する事は原理的には可能である。


C) JavaScriptを使用したブラウザ攻撃の可能性


JavaScript実装の多くが、JIT(実行時コンパイル)を行っているため、分岐命令やそれに伴った予測実行コードを意図的に生成することができると考えられる。サイドチャネルを作るためのキャッシュの破棄やキャッシュされたかどうかの判断は、巨大な配列を使用することで間接的に可能になる可能性がある。これによって、ブラウザに実装されているサンドボックス機能等のプロテクションが回避される可能性がある。


こんな感じでとりあえず、まとめてみた次第。ちょっと息切れして対策部分までは書けなかった。とりあえず、あたりが暗くなってきたので、買い物がてら散歩に出かける。

なんだかんだで今日もトータル10Km越えして、美味しく晩飯をいただく。(笑)

さて、今日でまた一歳歳を食った。なかなか歳なりに人生を達観できないでいる厄介な62歳である。まぁ、今年もせいぜいあれこれ悪あがきをしながら、これまでもらってきたものを世の中にお返ししていこうと思っている次第だ。

トラックバック(0)

トラックバックURL: https://www.kazamidori.jp/MT/mt-tb.cgi/3412

コメントする

月別 アーカイブ

この記事について

このページは、風見鶏が2018年1月 7日 21:45に書いた記事です。

ひとつ前の記事は「新年早々のMeltdown」です。

次の記事は「成人の日?」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。