Weitere ähnliche Inhalte Ähnlich wie [CB16] House of Einherjar :GLIBC上の新たなヒープ活用テクニック by 松隈大樹 (20) Kürzlich hochgeladen (10) [CB16] House of Einherjar :GLIBC上の新たなヒープ活用テクニック by 松隈大樹3. tl;dr
Heap Exploitation(x64 Linux/Glibc malloc)
"House of Einherjar" とは?
Glibc mallocにおける新しいheap exploitation手法で, malloc()
の戻り値をおおよそ任意なアドレスに強制させるものである.
通常, ユーザはmalloc()の戻り値のアドレスに対して読み書きを行える.
フラグメント防止のためにあるchunk同士の結合処理を利用する.
Well-sizedなchunk上でのOff-by-one Overflowが直後のchunkの
prev_sizeとPREV_INUSEのコントロールをもたらす.
Proof of Concept
http://ux.nu/6Rv6h
5. "struct malloc_chunk"
メモリブロックはfree()される際にfree listへとつながれる.
このとき, メモリブロックは"struct malloc_chunk"として扱われる.
ChunkのサイズはSIZE_SZ*2にアライメントされる.
(prev_size)
size
fd
bk
(not used)
(prev_size)
size
data
+
pads
SIZE_SZ
=8byte
User's
space
(a) in-used (b) free
図1 struct malloc_chunk
Shared with
previous chunk
Glibc malloc Chunk
6. 型 名称 説明
INTERNAL_SIZE_T prev_size 自身の直前にあるchunkのサイズ (shared)
INTERNAL_SIZE_T size 自身のサイズと現在の状態
struct malloc_chunk *fd (free list上で)前方につながっているchunkへのポインタ
struct malloc_chunk *bk (free list上で)後方につながっているchunkへのポインタ
表1: struct malloc_chunk
Glibc malloc Chunk
7. "struct malloc_chunk"
メモリブロックはfreeされる際にfree listへとつながれる.
このとき, メモリブロックは"struct malloc_chunk"として扱われる.
ChunkのサイズはSIZE_SZ*2にアライメントされる.
(prev_size)
size
fd
bk
(not used)
(prev_size)
size
data
+
pads
SIZE_SZ
=8byte
PMA
User's
space
(a) in-used (b) free
図1 struct malloc_chunk
Low 3 bits
mean chunk
status
Shared with
previous chunk
Glibc malloc Chunk
8. "struct malloc_chunk"
メモリブロックはfreeされる際にfree listへとつながれる.
このとき, メモリブロックは"struct malloc_chunk"として扱われる.
ChunkのサイズはSIZE_SZ*2にアライメントされる.
(prev_size)
size
fd
bk
(not used)
(prev_size)
size
data
+
pads
SIZE_SZ
=8byte
PMA
User's
space
(a) in-used (b) free
図1 struct malloc_chunk
Low 3 bits
mean chunk
status
[P]REV_INUSE
IS_[M]MAPPED
NON_MAIN_[A]RENA
Shared with
previous chunk
Glibc malloc Chunk
9. Free chunkはfree list(bin)につながれる
Small bins
MAX_FAST_SIZE < size < MIN_LARGE_SIZE
MAX_FAST_SIZE: 0xa0
MIN_LARGE_SIZE: 0x400
Unsorted bins
free()されたばかりのchunkが一時的に格納されるリスト.
サイズによる制限は無い.
Glibc malloc Bin
11. Glibc malloc Consolidating Chunks
メモリ確保と解放を繰り返しているとフラグメント化を起こし
てしまう
そこで, free()されるchunkと隣接するfree chunkの結合を考える.
自身の直前のchunkと隣接している.
自身の直後のchunkと隣接している.
PREV_INUSE bit
自身の直前に隣接するchunkが使用中か否かを判断するためのフラグ.
これが結合の際の判断基準となる.
12. Glibc malloc Consolidating Chunks
Chunkの結合処理はどこにある?
Glibcを読む.
free(p)
__libc_free(p)
_int_free(av, p, have_lock) <- これ!
16. Glibc malloc Consolidating Chunks
(prev_size)
size
prev
p
(a) prev_inuseのチェック
図4 結合
size = p->size
If not prev_inuse(p):
prevsize = p->prev_size
size += prevsize
p += -(long)(prevsize)
fd
bk
(not used)
(prev_size)
size 0
data
+
pads
p
17. Glibc malloc Consolidating Chunks
(prev_size)
size
(b) 再配置
図4 結合
size = p->size
If not prev_inuse(p):
prevsize = p->prev_size
size += prevsize
p += -(long)(prevsize)
p
fd
bk
(not used)
(prev_size)
size 0
data
+
pads
prev
p
p
18. Glibc malloc Consolidating Chunks
(prev_size)
size 1
p
(c) 結果
図4 結合
p
(prev_size)
size
fd
bk
(not used)
fd
bk
(not used)
(prev_size)
size 0
data
+
pads
prev
p
p
19. House of Einherjar Flaw / Flow
今のところ, これらのことが既知である
"p->prev_size"は, 直前に隣接するchunkと共有されうる.
"p->size"のPREV_INUSE bitを基にchunkの結合の可否を決定する.
新しいpの位置は"p->prev_size"により決定する.
"p = chunk_at_offset(p, -((long)prevsize))"
20. House of Einherjar Flaw / Flow
今のところ, これらのことが既知である
"p->prev_size"は, 直前に隣接するchunkと共有されうる.
"p->size"のPREV_INUSE bitを基にchunkの結合の可否を決定する.
新しいpの位置は"p->prev_size"により決定する.
"p = chunk_at_offset(p, -((long)prevsize))"
ここで, 以下の条件について考える
3つのchunkが存在する.
p0: well-sizedなサイズをもつchunk(p1->prev_sizeを内包する).
p1: small binサイズのchunk.
(p2: malloc_consolidate()を抑制するためのchunk.)
p0についてOff-by-oneでNUL byte('¥0')なOverflowが存在する.
21. House of Einherjar Flaw / Flow
(prev_size)
size
data
(prev_size)
size
data
+
pads
1
well-sized
shared
(a) Overflow前
図5 House of Einherjarの原理
p0 (used)
p1 (used)
24. House of Einherjar Flaw / Flow
(prev_size)
size
data
0xdeadbeef
size
data
+
pads
'¥0'
(c) Overflow後
図5 House of Einherjarの原理
p0 (free)
p1 (used)
shared
well-sized
size = p1->size
If not prev_inuse(p1):
prevsize = p1->prev_size
size += prevsize
p1 += -(long)(prevsize)
25. House of Einherjar Flaw / Flow
(prev_size)
size
data
0xdeadbeef
size
data
+
pads
'¥0'
(c) Overflow後
図5 House of Einherjarの原理
p0 (free)
p1 (used)
shared
well-sized
size = p1->size
If not prev_inuse(p1):
prevsize = 0xdeadbeef
size += prevsize
p1 += -(long)(prevsize)
26. House of Einherjar Flaw / Flow
House of Einherjarに必要なこと
うまくサイズの調整されたchunkがOff-by-oneでOverflowを起こす.
ターゲットとする領域の近くにfake chunkがある.
fd, bkメンバはfake chunk自身を指すようにすると簡単である.
ターゲットとする領域と"p1"のアドレスについての差分が計算可能である.
このとき, これら2つのアドレスのleakが必要となる.
free()時に"p1->size"が大きく変更されるのでその補正が可能である.
※fake chunkは何回か編集可能であると仮定する.
28. House of Einherjar Evaluation
メリット
メモリレイアウトにも依るがOff-by-oneなOverflowさえあればできる.
"House of Force"のような巨大なmalloc()を必要としない.
デメリット
fake chunkを置ける領域の近くしかmalloc()で取得できない.
2つのアドレスのleakが必要となる.
評価: "悪くはない"
29. House of Einherjar Countermeasures
"struct malloc_chunk"がよくないのでは?
そもそも"chunk->prev_size"が通常の書き込みにより上書きされること
がよくない.
そもそもBoundary Tagアルゴリズムだから仕方がない.
対策方法は?
Address checking
結合後の新しいchunkのアドレスは正しいか?
StackとHeapのアドレスは全然違う.
Return addressは守れる.
Heap内でのHouse of Einherjarには対応しきれない.