Slide 1

Slide 1 text

LLVM meets kernel @ntddk

Slide 2

Slide 2 text

whoami ● Yuma Kurogome(@ntddk) ● 慶應義塾大学 SFC B1, 武田研 ● 留年の危機 ● Synclogue Inc. ● Windows kernel, RCE, LLVM ← new!

Slide 3

Slide 3 text

whoami ● CTF – EpsilonDelta(一応) – sutegoma2(潜入) – Kazusa ● HackInTheBox KL – ROPが解けなかった

Slide 4

Slide 4 text

今回話すこと ● LLVM ● Return-oriented programming(ROP) ● LLVMによるROP緩和技術 ● LLVMLinux

Slide 5

Slide 5 text

LLVM

Slide 6

Slide 6 text

詳しくは...

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

LLVMの構成 ● Frontend ● Middlend ● Backend

Slide 9

Slide 9 text

Frontend ● 字句解析 ● 構文解析 ● 意味解析 ● コード生成 – LLVM IR ● Frontendを実装するだけで任意の言語のコンパ イラが作れる – MiddlendとBackendはLLVMデフォルトでも十分

Slide 10

Slide 10 text

Middlend ● PassによるLLVM IRの解析と最適化 – 関数全てに対するPass – ループ文に対するPass – ジャンプのない一連の処理に対するPass – etc... ● 自分だけのPassでみんなと差をつけろ

Slide 11

Slide 11 text

Backend ● アセンブリ生成 ● 実行オブジェクト生成 ● LLVM IRの実行(JIT) ● コード生成(トランスレータ) ● 独自の言語のソースコードを生成したい場合は Backendを実装する必要がある

Slide 12

Slide 12 text

Clang ● C, C++, Obj-C, Obj-C++のFrontend ● C++14(N3797)の機能を完全に実装 ● BSDライクなライセンス – gccはGPLv3

Slide 13

Slide 13 text

ROP

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

脆弱性対策技術 ● StackGuard – リターンアドレス付近に乱数を配置 ● StackSheild – リターンアドレスを離れた位置に保存 ● ASLR – アドレスのランダマイズ – 攻撃の成功率を下げる ● Exec Shield – データ実行防止

Slide 16

Slide 16 text

ROP ● 脆弱性攻略のための一技術 – Exec Shieldを突破する ● Return-oriented programming ● 短いコードブロックを組み合わせてシェルコー ドとする – ROP gadgets – シェルコードとして使える命令とリターンのセット – 命令をずらして解釈することも – ASLRがかかっていないファイルを利用

Slide 17

Slide 17 text

ROP gadgets 684a0f4e: pop eax ret 684a2367: pop ecx ret 684a123a: mov[ecx], eax ret 0x684a123a 0xfeedface 0xdeadbeef 0x684a2367 0x684a0f4e

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

Return-oriented rootkit ● Rootkit – カーネル構造体などを書き換える – 悪意のあるプログラムを隠蔽 ● Return-oriented rootkit – Return-Oriented Rootkits: Bypassing Kenrel Code Integrity Protection Mechanism – ROPを利用したrootkit – ROPでカーネルの整合性検証をバイパスする

Slide 20

Slide 20 text

Return-oriented rootkit ● カーネルの整合性検証 – 未許可のLKMを実行しない ● LKMにシグネチャを付加して検証 – みんな大好きVMM ● BitVisorとか – 書き込み可能なアドレスの実行権限を外す

Slide 21

Slide 21 text

Return-oriented rootkit ● rootkitと名が付いているがLKMをロードする わけではない ● 要するにカーネルモードでのROP ● LKMにバッファオーバーフローなどの脆弱性が ある場合の攻撃手法

Slide 22

Slide 22 text

LLVMによるROP緩和技術

Slide 23

Slide 23 text

Return-less kernel ● ROPでは任意の命令とリターンを組み合わせる ● じゃあカーネルから リターンをなくせば いいじゃん ● Defeating Return-Oriented Rootkits With “Return-less” Kernels ● せっかくだから俺はLLVMを使うぜ

Slide 24

Slide 24 text

LLVMのFreeBSD対応 ● まともに動くFreeBSDカーネルをビルドできる ようになったのは2009年2月25日 ● Return-less kernelが発表されたのは2010年4月 ● FreeBSD 8.0対象

Slide 25

Slide 25 text

Return-less kernel ● 3つの手法でカーネルからreturnを除去 – Return indirection – Register allocation – Peephole optimization ● LLVM backendを中心に実装 – マシン語の最適化 – 1命令を減らす最適化はバックエンドでのみ可能

Slide 26

Slide 26 text

Return indirection ● リターンアドレスをテーブルから取得してくる – retは直接スタック上の戻り先アドレスを読み込む – 別の位置にあるリターンアドレスを読み込んでから そのアドレスにジャンプするようにすればガジェッ トを無効化できる

Slide 27

Slide 27 text

Return indirection ● call, retを新しい形式に置き換える push $index jmp dst ... pop %reg jmp *RegAddrBase(%reg)

Slide 28

Slide 28 text

Register allocation ● Return indirectionだけでretを除去できるとは 限らない ● x86は可変長であるためコンパイラがretを生成 してしまうことがある mov %eax, %ebx -> 89 c3 ● movなのに何故かret(0xc3)に... ● LLVM IRの仮想レジスタマッピング時に調整

Slide 29

Slide 29 text

Register allocation ● llvm::Spiller ● LLVMのレジスタ割り当てアルゴリズム – Simple scan – Local scan ● これら2つは仮想レジスタから直接マッピング – Linear scan ● より高度な割り当て

Slide 30

Slide 30 text

Register allocation ● Linear scanを利用 ● X86RegisterInfo.tdを拡張 – x86におけるレジスタ記述ファイル ● 危険なレジスタ割り当てにアノテーション ● 再割り当て ● ご安全に!

Slide 31

Slide 31 text

Peephole optimization ● コード中の0xc3を書き換える – 即値でもretと解釈してROPに使える cmp $0xc3,%ecx → mov $0xc4, %reg dec %reg cmp %reg, %ecx

Slide 32

Slide 32 text

Peephole optimization ● FreeBSD 8.0におけるコード 0xFFFFFFFF801A4F01: E9 C3 00 00 00 jmpq 0xFFFFFFFF801A4FC9 ● この0xc3の意味は?

Slide 33

Slide 33 text

Peephole optimization ● jmpq命令の直後からのオフセット ● 相対アドレスの調整で0xc3を排除できる 0xFFFFFFFF801A4F01: E9 C4 00 00 00 jmpq 0xFFFFFFFF801A4FCA 0xFFFFFFFF801A4F06: 90 nop

Slide 34

Slide 34 text

LLVMLinux

Slide 35

Slide 35 text

+

Slide 36

Slide 36 text

LLVMLinux

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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;

Slide 39

Slide 39 text

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");

Slide 40

Slide 40 text

Return-less Linux kernel ● そろそろLLVMでLinuxをビルドできそう ● LinuxでもReturn-less kernelを実現できたらい いよね ● GSoCとか... ● OSvってどうなの