coding, photo, plant and demo

*IEの脆弱性とUse-After-Free

tech webkit 20140504 074141

IEの脆弱性は何を引き起こすか

先日ほぼ全てのIEで任意のコードが実行されうるという、非常に大きな脆弱性が見つかりました。
任意のコードが実行されるというのは、場合にもよりますが大変マズいことになります。

ちょっと前のOpenSSLのHeart bleedも問題でしたが、あれはただ少しメモリをダンプできるだけです。任意のコードが実行できたら、メモリのダンプなど当たり前です。
最悪どんなことが起きうるかといえば、ちょっと想像するだけで下記のような事態に成り得ます。
  • PC内の情報が漏れる
    • 個人情報まるだし
    • サイトのパスワードやセッションが奪われ、不正にクレジットが使用されたり、銀行の振込が行われる
  • バックドアが仕掛けられる
    • あなたのキー入力や画面、さらにカメラを使えばあなたの顔も監視できます
    • 新たな攻撃の起点となり、警察が無能だとあなたが犯人の扱いとして捕まります
    • 組織内のLANへアクセスする踏み台として利用されます (例えば会社中の機密データが筒抜けになります)

対策

というわけで非常に恐ろしいのですが、対策は下記に有るように簡単です。

[回避策まとめ] セキュリティ アドバイザリ 2963983 – Internet Explorer の脆弱性により、リモートでコードが実行される
http://blogs.technet.com/b/jpsecurity/archive/2014/04/30/workarounds-for-security-advisory-2963983.aspx

大きく2通りの対策があります。

  • 問題の有るVMLを無効にする
  • 保護機能を有効にする
    • x64かつWindows7以降なら拡張保護モードを有効にする
    • そうでなければ、EMET (Enhanced Mitigation Experience Toolkit)を有効にする

これらについてちょっと深堀りしてみます。

脆弱性から任意のコードの実行への道

まず、問題の有るVMLですが、具体的には何がまずく、どういうことが起きえるのでしょうか?
脆弱性の原因はVML(Vector Markup Language)を処理するVGX.DLL内にあります。

Protection strategies for the Security Advisory 2963983 IE 0day
http://blogs.technet.com/b/srd/archive/2014/04/30/protection-strategies-for-the-security-advisory-2963983-ie-0day.aspx

によるとVGX.DLL内のUse-After-Freeという脆弱性が問題のようです。Use-After-Freeとは、一度解放したメモリブロックを再度使ってしまうというバグを指します。下記のようにfreeした後の確保されていない領域にアクセスするバグです。

  1. 1char *p = malloc(size);
  2. 2// do something
  3. 3free(p);
  4. 4// do something
  5. 5p[0] = 1;

これだけコードが短いとありえないバグだと思いますが、GCと参照カウンタと生ポインタが混在するようなブラウザのように複雑なプログラムでは、解放されたメモリを触らないようにプログラム全体を保証することは実は極めて困難であります。よって、後から後からこういったバグが見つかることはよくあります。

ただ、実際はこの例ではクラッシュする可能性はありますが攻撃には利用することは難しいでしょう *0 。実際に攻撃に利用しやすいパターンは、vtblを持つオブジェクトのUse-After-Freeです。

  1. 1class Node {
  2. 2 virtual void draw();
  3. 3};
  4. 4
  5. 5Node *p = new Node;
  6. 6// do something
  7. 7delete p;
  8. 8// do something
  9. 9p->draw();

vtblとは仮想関数を使った時にできる関数ポインタの配列です。この例だとpの指すNodeのインスタンスはNodeのvtblへのアドレスが含まれています。
このバグを利用して攻撃するには、まずdeleteの後にNodeとほぼ同じサイズのフェイクのオブジェクトを確保します。そして、解放したはずのオブジェクトのメソッドを呼ぶコードに飛ぶように仕向ければ偽のvtblを使わせることが出来、制御を奪うことが出来ます。

問題は偽のvtblの指し示す先に攻撃コード(shellcodeと呼びます)を置く方法です。これにはHeap sprayを用います。この詳しい手法は図や実践例を交えないと説明が難しいので、下記のチュートリアルを参考にしてください。

Part 9: Spraying the Heap [Chapter 2: Use-After-Free] – Finding a needle in a Haystack
http://www.fuzzysecurity.com/tutorials/expDev/11.html

この場合、MS13-009と呼ばれるIE8のUse-After-Freeの脆弱性を利用して任意のコードを実行しています。この脆弱性は具体的には、とある操作を行った後に再レイアウトが発生すると、解放済みのオブジェクトの仮想関数を呼ぶ(この場合vtbl+0x70が指すアドレスを呼ぶ)、というものです。

簡単にこのサンプルを解説すると、freeが起きた直後に0x0c0c0c0cというバイナリを文字列として1150個確保し、オブジェクトが存在していた場所を0x0c0c0c0cで埋め、vtblを0x0c0c0c0cに上書きします。そして0x0c0c0c0c+0x70の位置にスタックピボット(stack vipot)と呼ばれるコードのアドレスが、0xc0c0c0c0からは攻撃コード(ROP-chain)が埋まるようにヒープを埋め尽くします。このように所定のアドレスを埋めるためだけに、大量にオブジェクトを作りヒープを埋めることをHeap sprayと呼びます。

スタックピボットは名前の通り、スタック(ESP)を入れ替えることで、この場合0x0c0c0c0cが入っているEAXとESPが交換されてRETが呼ばれるコードになります。スプレーが終わったら再レイアウトを起こします。するとスタックピボットが発動しESP=0xc0c0c0c0としてRETが呼ばれるわけですが、0xc0c0c0c0からのメモリにはROP(Return Oriented Program)-chainが埋め込まれており、それが順々に実行されていきます。ROPではVirtualProtectを呼び、DEP(Data Execution Prevention, データの実行防止)を無効化して、攻撃コードの中核へと移るのが攻撃の定番で、このサンプルもそうなっています。

例ではダイアログを出しているだけですが、ここまで来るとバックドアを仕掛けるなど、なんでも可能となります。(後述の保護が機能していなければ)

保護とはなにか

問題を興すVMLを無効にする以外にの対策として、保護を有効にするというものが有りました。
これはどういうことでしょうか。保護、そして拡張保護モードとはなにかは下記にあります。

IE10 におけるメモリ保護機能の強化
http://blogs.msdn.com/b/ie_ja/archive/2012/03/16/ie10.aspx
IE10ではASLRが導入されROPを困難にしました。ただし、ASLRは一つでもASLRに対応していないDLLがあると、全てを台無しにする可能性があります。

拡張保護モード
http://blogs.msdn.com/b/ie_ja/archive/2012/03/21/enhanced-protected-mode.aspx
まとめると拡張保護モードにすると「コンテンツプロセスが64bitかつ非常に制限された権限で動く」と言って良さそうです。

IE10 & IE11 : 拡張保護モードの実態
http://blogs.technet.com/b/jpieblog/archive/2013/11/30/3614857.aspx]
具体的に、コンテンツが動くプロセスがどういった権限(WindowsではIntegrityu Levelと呼ぶ)で動くか等を説明しています。

これらの前提としてIE8からは、タブごとにプロセスを分離しています。

IE8 のプロセスモデルについて
http://blogs.technet.com/b/jpieblog/archive/2010/05/10/3331472.aspx

このように色々やっているわけですが、保護とは大きく2つの意味があります。

  • 脆弱性によって乗っ取られないようにする
  • 乗っ取られても好き放題はできないようにする

前者はDEPやASLR、64bit化、SAFESEHといった技術で、乗っ取られないようにハッカーの使う技を無効化するための技術です。ただ、どう頑張っても全ての穴を塞ぐのはブラウザのように複雑なプログラムでは非常に難しいため、仮に乗っ取られても被害を最小限する技術も必要となります。それが後者でsandboxと呼ばれます。sandboxは下記の2つを行うことで成り立ちます。

  • コンテンツを実行するプロセスをブラウザ本体と分離する
  • コンテンツを実行するプロセスの権限を極限まで奪う

IEの場合は、プロセスの分離まではしていたけど、標準設定では拡張保護モードが有効ではなく、十分に権限を奪うところまでは有効に成っていなかったのが問題といえます。ただ、権限を絞ってしまうと、それを想定していない従来のプラグインやActiveXが動作しなくなるトラブルを抱えることになるため、IEとしては判断が難しかったのかもしれません。

ChromeやFirefoxはどの程度安全か?

「なんかよくわかんねーけど、IEが危ないらしいから、ChromeかFirefoxを使うわ」と思う人も多いと思いますが、ではIE以外のブラウザはどの程度安全なのでしょうか?

まずChromeはかなり安全だと思います。というのも、IEが拡張保護などで対策していることは最初から実装済みで実績があります。そもそもコンテンツが動く部分を別のプロセス(Chromium用語ではRenderer Process)に追い出すsandboxを実装した先駆者がChromeです。sandboxには掛けられるだけの制約を掛けて、極力乗っ取られても何も出来ないようにしています。

Windows版でどのようなポリシーを設定しているかは下記で分かります。
http://git.chromium.org/gitweb/?p=chromium/src.git;a=blob;f=content/common/sandbox_win.cc;h=7c3048aadbb477209d5a63b44b2f845bc33378ae;hb=020bc9ffc192487f12e81b75e7ef42a23db9bc3e

ただし、そもそも権限を制限するのはOSにそういった仕組みがなければ成り立ちません。例えばWindowsのIntegrity Levelと呼ばれる権限を変える事自体が、基本的にはVista以降ですし、App Containerと呼ばれる強力なsandboxの仕組みはWindows8からしか使えません。例え安全と言われるChromeを使っていても、XP上では常に危険に晒されているといっても嘘ではないと思います。

対してFirefoxですが、現状プロセス分離すらできていないので、IEよりもさらに危険なのではないかと思います。例えばFirefoxとChromeで使っているlibjpeg_turboに脆弱性が発見されたとします。このときFirefoxは乗っ取られてしまっても、Chromeの場合はさらにsandboxを破らなくてはいけないため、ChromeはFirefoxと比べて格段に攻撃を成功させることは難しくなります。もちろんプロセス分離の重要さはMozillaも認識しており、以前からElectrolysisというプロジェクトでプロセス分離を行おうとしているのですが、まだ正式リリースには至っておりません。

事実、今年のPwn2OwnでもIEを含む主要4ブラウザの中でFirefoxがもっともexploitされてしまいました。下記の記事でも依然として最もセキュリティが低いのはFirefoxであり、Firefoxだけsandbox機構がないことを問題視しています。

Firefox is still the least secure web browser, falls to four zero-day exploits at Pwn2Own
http://www.extremetech.com/computing/178587-firefox-is-still-the-least-secure-web-browser-falls-to-four-zero-day-exploits-at-pwn2own

とはいえChromeもPwn2Ownでたまにexploitされることもあり、完全に安全というわけではありません。今年はsandboxを迂回する方法が見つかったそうです。よく見つけるよな…

「Google Chrome」がアップデート、“Pwn2Own 2014”で明らかにされた脆弱性を4件修正
http://www.forest.impress.co.jp/docs/news/20140317_639917.html

あとsandboxがあればバックドアを仕掛けるような大技は防止できますが、現状のChromeでもiframeで読み込まれたページは親と同じsandbox(プロセス)で動くため、他のサイトのcookieを盗まれセッションハイジャックなどに利用される危険はあります。これに関してChromeではOut-of-Process iframesという技術で対応しようとしています。

http://www.chromium.org/developers/design-documents/oop-iframes

まず大丈夫とはいえ、怪しいサイトに気軽に訪れない自衛の精神は持ってた方がいいですね。

最後に

長くなってきたのでこの辺で。

書いてて思ったんですが、そもそもなぜブラウザでは重大な脆弱性が毎年のように見つかるのか、それはブラウザの構造の問題では無いのか、ブラウザが構造的に抱えるパフォーマンス等の問題も含めてそれは克服可能なのか、主戦場となりつつあるモバイルではブラウザの地位が低下しているが克服したところで流れを変えることはできるのか、ブラウザは戦艦大和的存在になりつつある危険を孕んでいるのでは(あるいはイノベーションのジレンマにハマりつつある)、等と色々と考えることはありそうな気がしました。
*0 : とも言い切れなくて、実はこういう1バイトを書き換えるパターンがvtbl書き換えよりも使いやすかったりもします