master canary forging: 新しいスタックカナリア回避手法の提案 by 小池 悠生 -...
TRANSCRIPT
Master Canary Forging新しいスタックカナリア回避手法の提案
自己紹介
● 小池 悠生(こいけ ゆうき)○ 16歳、学生
● CTFにハマっていた
○ DEF CON 2014 Finalist○ CODEGATE Junior 2015 Winner○ 引退視野
概要
● 動機
● Stack Canary● これまでの回避手法
● Master Canary Forging● 手法の評価と対策
概要
● 動機
● Stack Canary● これまでの回避手法
● Master Canary Forging● 手法の評価と対策
動機
● 僕はROPが好き
○ だからStack Based Buffer Overflowが好き
○ だからStack Canaryは嫌い
● Stack Canaryは強い
○ 回避出来る条件を考えるのは価値がある
○ 良い回避方法はないか?
概要
● 動機
● Stack Canary● これまでの回避手法
● Master Canary Forging● 手法の評価と対策
Stack Canary
● BOFによる攻撃を阻止したい
○ return addressが書き換えられたか判定したい
■ されていたらプロセスを殺す
○ 指標を作ればいい
■ BOFの前後で値が変わるようにする
Stack Canary
return address
frame pointer
local variables
● 指標を追加する
Stack Canary
return address
frame pointer
canary 0xdeadbeef
local variables
● BOFが起こると...
Stack Canary
canaryoverwritten
● canaryの値が変わるので、攻撃を検知出来る
Stack Canary
modified0x41414141
● canaryの値が変わるので、攻撃を検知出来る
Stack Canary
modified0x41414141
Not 0xdeadbeefAttack Detected
Stack Canary
● BOFによる攻撃を阻止したい
○ return addressが書き換えられたか判定したい
■ されていたらプロセスを殺す
○ 指標を作ればいい
■ BOFの前後で値が変わるようにする
Stack Canary
● BOFによる攻撃を阻止したい
○ return addressが書き換えられたか判定したい
■ されていたらプロセスを殺す
○ 指標を作ればいい
■ BOFの前後で値が変わるようにする
● これ、保証できる??
● canaryの値が変わらないと検知できない
Stack Canary
modified0xdeadbeef
● canaryの値が変わらないと検知できない
Stack Canary
modified0xdeadbeef
return address
任意の値に出来る
● canaryの値が変わらないと検知できない
Stack Canary
⇒ACE(任意のコード実行)
Stack Canary
● Stack Canaryの種類
○ Random■ 元となる値が分からないようにする
■ プロセスの起動時に値をランダムに決める
○ Terminator■ ’\0’ 等が含まれるようにする
■ 元の値にしづらい
Stack Canary
● master canaryとstack上のcanaryの比較
概要
● 動機
● Stack Canary● これまでの回避手法
● Master Canary Forging● 手法の評価と対策
● ex1.c
回避手法1: __stack_chk_failを避ける
#include <stdio.h>void bof(int (*print)(const char *)) { char buf[16]; scanf("%s", buf); print(buf);}int main(void) { bof(puts);}
● ex1.c
#include <stdio.h>void bof(int (*print)(const char *)) { char buf[16]; scanf("%s", buf); print(buf);}int main(void) { bof(puts);}
回避手法1: __stack_chk_failを避ける
return addressframe pointer
canary
local variables
arguments
● ex1.c
回避手法1: __stack_chk_failを避ける
overwritten
arguments
#include <stdio.h>void bof(int (*print)(const char *)) { char buf[16]; scanf("%s", buf); print(buf);}int main(void) { bof(puts);}
● ex1.c
回避手法1: __stack_chk_failを避ける
overwritten
arguments
#include <stdio.h>void bof(int (*print)(const char *)) { char buf[16]; scanf("%s", buf); print(buf);}int main(void) { bof(puts);} 関数ポインタかつ引数
● ex2.c
回避手法2: canaryをリークする
#include <stdio.h>
int main(void) { char buf[16]; scanf("%s", buf); printf(buf); fread(buf, sizeof(char), 32, stdin);}
● ex2.c
回避手法2: canaryをリークする
#include <stdio.h>
int main(void) { char buf[16]; scanf("%s", buf); printf(buf); fread(buf, sizeof(char), 32, stdin);}
書式指定子攻撃
回避手法2: canaryをリークする
$ gdb ./ex2 -q(gdb) b 4Breakpoint 1 at 0x8048532: file ex2.c, line 4.(gdb) rBreakpoint 1, main () at ex2.c:44 scanf("%s", buf);(gdb) x/12xw $esp0xffffce60: 0xffffd129 0x0000002f 0x0804a000 0x080485e20xffffce70: 0x00000001 0xffffcf34 0xffffcf3c 0xf7e3539d0xffffce80: 0xf7faa3c4 0xf7ffd000 0x0804859b 0x48d09200(gdb) c%11$x48d09200
● stack canaryのどこを突破口にしているか?
○ 回避手法1: __stack_chk_failの回避
■ 検知、強制終了を行うところ
○ 回避手法2: canaryをリークする
■ stackに入ったcanary
回避手法の本質
● stack canaryのどこを突破口にしているか?
○ 回避手法1: __stack_chk_failの回避
■ 検知、強制終了を行うところ
○ 回避手法2: canaryをリークする
■ stackに入ったcanary○ 回避手法3: master canaryを書き換える
■ stack canaryの元の値
回避手法の本質
概要
● 動機
● Stack Canary● これまでの回避手法
● Master Canary Forging● 手法の評価と対策
● 以下を仮定
■ Linux Kernel 3.19■ glibc 2.21■ ASLRは有効
Master Canary Forging
● master canaryはどこにある?
○ glibcを読む
Master Canary Forging
static voidsecurity_init (void){ /* Set up the stack checker's canary. */ uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);#ifdef THREAD_SET_STACK_GUARD THREAD_SET_STACK_GUARD (stack_chk_guard);#else __stack_chk_guard = stack_chk_guard;#endif
● master canaryはどこにある?
○ glibcを読む
Master Canary Forging
static voidsecurity_init (void){ /* Set up the stack checker's canary. */ uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);#ifdef THREAD_SET_STACK_GUARD THREAD_SET_STACK_GUARD (stack_chk_guard);#else __stack_chk_guard = stack_chk_guard;#endif
実体への代入
● master canaryはどこにある?
○ glibcを読む
Master Canary Forging
static voidsecurity_init (void){ /* Set up the stack checker's canary. */ uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);#ifdef THREAD_SET_STACK_GUARD THREAD_SET_STACK_GUARD (stack_chk_guard);#else __stack_chk_guard = stack_chk_guard;#endif
● master canaryはどこにある?
○ THREAD_SET_STACK_GUARD■ 7アーキテクチャにて定義
■ canaryがTLS(thread local storage)に入る
■ 定義されていないならmaster canaryは.bssへ
Master Canary Forging
● master canaryを書き換えるには
○ .bssにある時
■ 任意のアドレス書き換えができればいいだけ
Master Canary Forging
● master canaryを書き換えるには
○ .bssにある時
■ 任意のアドレス書き換えができればいいだけ
○ TLSにある時?
Master Canary Forging
● master canaryを書き換えるには
○ .bssにある時
■ 任意のアドレス書き換えができればいいだけ
○ TLSにある時?
■ そもそもTLS領域はどこに確保されるのか?
Master Canary Forging
● TLS領域はどこにある?
○ glibcを読む
Master Canary Forging
void * internal_function _dl_allocate_tls_storage (void){ void *result; size_t size = GL(dl_tls_static_size);#if TLS_DTV_AT_TP size += (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1) & ~(GL(dl_tls_static_align) - 1);#endif /* Allocate a correctly aligned chunk of memory. */ result = __libc_memalign (GL(dl_tls_static_align), size);
● TLS領域はどこにある?
○ _dl_allocate_tls_storageが確保を行う関数
■ 内部で__libc_memalignが呼ばれる
● __libc_memalignは内部でmmapを呼ぶ
○ 結局はmmapによって確保されたどこか
■ ASLRの影響を受けるため書き換えが難しい
Master Canary Forging
● mmapで確保された領域の特徴:
○ 常にどこかの領域と隣接している
Master Canary Forging
● Mapped Area Based Buffer Overflow
Master Canary Forging
target area
● Mapped Area Based Buffer Overflow○ まずmmapを使って領域を確保する
○ 確保した領域が目的の領域の上に来るようにする
Master Canary Forging
mapped area
target area
● Mapped Area Based Buffer Overflow○ まずmmapを使って領域を確保する
○ 確保した領域が目的の領域の上に来るようにする
○ 確保した領域でBOFを起こす
○ 十分なサイズなら、隣接した領域も上書き出る
Master Canary Forging
overwritten
● Mapped Area Based Buffer Overflow○ これでmaster canaryを書き換えられそう!
○ でも、攻撃者はmmapを呼べるの?
Master Canary Forging
● Mapped Area Based Buffer Overflow○ これでmaster canaryを書き換えられそう!
○ でも、攻撃者はmmapを呼べるの?
■ はい
Master Canary Forging
● Mapped Area Based Buffer Overflow○ これでmaster canaryを書き換えられそう!
○ でも、攻撃者はmmapを呼べるの?
■ はい
■ malloc
Master Canary Forging
● Mapped Area Based Buffer Overflow○ これでmaster canaryを書き換えられそう!
○ でも、攻撃者はmmapを呼べるの?
■ はい
■ malloc■ “When allocating blocks of memory larger than
MMAP_THRESHOLD bytes, the glibc malloc() implementation allocates the memory as a private anonymous mapping using mmap(2).”
Master Canary Forging
● Mapped Area Based Buffer Overflow○ 使える条件は以下の2つ
■ heapのallocateを自由に行える
■ Heap Based BOFが起こる
Master Canary Forging
1. master canaryの書き換え
a. .bssにある時
i. 任意のアドレス書き換えで書き換える
b. TLSにある時
i. Mapped Area Based BOFを使う
2. Stack Based BOFを起こす
Master Canary Forging
概要
● 動機
● Stack Canary● これまでの回避手法
● Master Canary Forging● 手法の評価と対策
● 評価
○ 使いづらい
■ 2種類の脆弱性が必要
■ 普通Heap Based Buffer Overflowだけで十分
○ Mapped Area Based BOF単体は使いやすい
■ TLSには関数ポインタテーブルがある場合あり
手法の評価と対策
● 対策
○ Random XOR Canaryを使う
■ canary = master canary ^ stack pointer○ ガードページを設ける
手法の評価と対策
https://github.com/potetisensei/MasterCanaryForging-PoC/
PoC
御静聴ありがとうございました
なんでも質問してください。