LLVM meets kernel

LLVM meets kernel

第九回 カーネル/VM探検隊 発表資料 http://peatix.com/event/22490 #kernelvm

5c6358240ec94522f70cf7b0e657f58f?s=128

Yuma Kurogome

December 08, 2013
Tweet

Transcript

  1. LLVM meets kernel @ntddk

  2. whoami • Yuma Kurogome(@ntddk) • 慶應義塾大学 SFC B1, 武田研 •

    留年の危機 • Synclogue Inc. • Windows kernel, RCE, LLVM ← new!
  3. whoami • CTF – EpsilonDelta(一応) – sutegoma2(潜入) – Kazusa •

    HackInTheBox KL – ROPが解けなかった
  4. 今回話すこと • LLVM • Return-oriented programming(ROP) • LLVMによるROP緩和技術 • LLVMLinux

  5. LLVM

  6. 詳しくは...

  7. LLVM • プログラムの最適化を支援するコンパイラ基盤 • 任意の言語 → LLVM IR → 任意の言語

  8. LLVMの構成 • Frontend • Middlend • Backend

  9. Frontend • 字句解析 • 構文解析 • 意味解析 • コード生成 –

    LLVM IR • Frontendを実装するだけで任意の言語のコンパ イラが作れる – MiddlendとBackendはLLVMデフォルトでも十分
  10. Middlend • PassによるLLVM IRの解析と最適化 – 関数全てに対するPass – ループ文に対するPass – ジャンプのない一連の処理に対するPass

    – etc... • 自分だけのPassでみんなと差をつけろ
  11. Backend • アセンブリ生成 • 実行オブジェクト生成 • LLVM IRの実行(JIT) • コード生成(トランスレータ)

    • 独自の言語のソースコードを生成したい場合は Backendを実装する必要がある
  12. Clang • C, C++, Obj-C, Obj-C++のFrontend • C++14(N3797)の機能を完全に実装 • BSDライクなライセンス

    – gccはGPLv3
  13. ROP

  14. 脆弱性対策技術 • scanf("%s", buf); – EIP 0x41414141からが戦い • プログラムに脆弱性があっても悪用されない機 能の実現

  15. 脆弱性対策技術 • StackGuard – リターンアドレス付近に乱数を配置 • StackSheild – リターンアドレスを離れた位置に保存 •

    ASLR – アドレスのランダマイズ – 攻撃の成功率を下げる • Exec Shield – データ実行防止
  16. ROP • 脆弱性攻略のための一技術 – Exec Shieldを突破する • Return-oriented programming •

    短いコードブロックを組み合わせてシェルコー ドとする – ROP gadgets – シェルコードとして使える命令とリターンのセット – 命令をずらして解釈することも – ASLRがかかっていないファイルを利用
  17. ROP gadgets 684a0f4e: pop eax ret 684a2367: pop ecx ret

    684a123a: mov[ecx], eax ret 0x684a123a 0xfeedface 0xdeadbeef 0x684a2367 0x684a0f4e
  18. None
  19. Return-oriented rootkit • Rootkit – カーネル構造体などを書き換える – 悪意のあるプログラムを隠蔽 • Return-oriented

    rootkit – Return-Oriented Rootkits: Bypassing Kenrel Code Integrity Protection Mechanism – ROPを利用したrootkit – ROPでカーネルの整合性検証をバイパスする
  20. Return-oriented rootkit • カーネルの整合性検証 – 未許可のLKMを実行しない • LKMにシグネチャを付加して検証 – みんな大好きVMM

    • BitVisorとか – 書き込み可能なアドレスの実行権限を外す
  21. Return-oriented rootkit • rootkitと名が付いているがLKMをロードする わけではない • 要するにカーネルモードでのROP • LKMにバッファオーバーフローなどの脆弱性が ある場合の攻撃手法

  22. LLVMによるROP緩和技術

  23. Return-less kernel • ROPでは任意の命令とリターンを組み合わせる • じゃあカーネルから リターンをなくせば いいじゃん • Defeating

    Return-Oriented Rootkits With “Return-less” Kernels • せっかくだから俺はLLVMを使うぜ
  24. LLVMのFreeBSD対応 • まともに動くFreeBSDカーネルをビルドできる ようになったのは2009年2月25日 • Return-less kernelが発表されたのは2010年4月 • FreeBSD 8.0対象

  25. Return-less kernel • 3つの手法でカーネルからreturnを除去 – Return indirection – Register allocation

    – Peephole optimization • LLVM backendを中心に実装 – マシン語の最適化 – 1命令を減らす最適化はバックエンドでのみ可能
  26. Return indirection • リターンアドレスをテーブルから取得してくる – retは直接スタック上の戻り先アドレスを読み込む – 別の位置にあるリターンアドレスを読み込んでから そのアドレスにジャンプするようにすればガジェッ トを無効化できる

  27. Return indirection • call, retを新しい形式に置き換える push $index jmp dst ...

    pop %reg jmp *RegAddrBase(%reg)
  28. Register allocation • Return indirectionだけでretを除去できるとは 限らない • x86は可変長であるためコンパイラがretを生成 してしまうことがある mov

    %eax, %ebx -> 89 c3 • movなのに何故かret(0xc3)に... • LLVM IRの仮想レジスタマッピング時に調整
  29. Register allocation • llvm::Spiller • LLVMのレジスタ割り当てアルゴリズム – Simple scan –

    Local scan • これら2つは仮想レジスタから直接マッピング – Linear scan • より高度な割り当て
  30. Register allocation • Linear scanを利用 • X86RegisterInfo.tdを拡張 – x86におけるレジスタ記述ファイル •

    危険なレジスタ割り当てにアノテーション • 再割り当て • ご安全に!
  31. Peephole optimization • コード中の0xc3を書き換える – 即値でもretと解釈してROPに使える cmp $0xc3,%ecx → mov

    $0xc4, %reg dec %reg cmp %reg, %ecx
  32. Peephole optimization • FreeBSD 8.0におけるコード 0xFFFFFFFF801A4F01: E9 C3 00 00

    00 jmpq 0xFFFFFFFF801A4FC9 • この0xc3の意味は?
  33. Peephole optimization • jmpq命令の直後からのオフセット • 相対アドレスの調整で0xc3を排除できる 0xFFFFFFFF801A4F01: E9 C4 00

    00 00 jmpq 0xFFFFFFFF801A4FCA 0xFFFFFFFF801A4F06: 90 nop
  34. LLVMLinux

  35. +

  36. LLVMLinux

  37. 現状 • LLVMでLinuxカーネルをビルドしたい! – Linuxカーネルはgccの拡張機能と癒着 – LLVM/Clangはgccの規格違反の挙動を絶対に実装 しない • LLVMへの機能追加とカーネルへのパッチで実

    現 – gcc拡張の闇を取り除く
  38. gcc拡張の闇 • Variable length arrays in structs (VLAIS) – Variable

    length arrayの拡張 – 構造体内で配列の長さを実行時指定 – iptablesやHMACなどで利用されている struct foo_t { char a[n];/* Explicitly not allowed by C99/C11 */ } foo;
  39. gcc拡張の闇 • __builtin_constant_pによる定数検出の回避 – LLVM Bug 4898 • Inline syntax

    handling – GNU89 • __initと__exit • レジスタ変数 – x86 register unsigned long current_stack_pointer asm("esp") __used; – ARM register unsigned long current_sp asm ("sp");
  40. Return-less Linux kernel • そろそろLLVMでLinuxをビルドできそう • LinuxでもReturn-less kernelを実現できたらい いよね •

    GSoCとか... • OSvってどうなの