Upload
code-blue
View
399
Download
1
Embed Size (px)
Citation preview
CODE BLUE 2016.10.20
@st4g3r
Hiroki MATSUKUMA
(@st4g3r)
新米ペンテスター サイバーディフェンス研究所所属
CTF Player TokyoWesterns
興味のあること Exploitation
GLIBC malloc (現時点では)
$whoami
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
概要
Glibc malloc Chunk
Bin
Consolidating Chunks
House of Einherjar Flaw / Flow
Demo
Evaluation
Countermeasures
"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'sspace
(a) in-used (b) free図1 struct malloc_chunk
Shared withprevious chunk
Glibc malloc Chunk
型 名称 説明
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
"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'sspace
(a) in-used (b) free図1 struct malloc_chunk
Low 3 bitsmean chunk
status
Shared withprevious chunk
Glibc malloc Chunk
"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'sspace
(a) in-used (b) free図1 struct malloc_chunk
Low 3 bitsmean chunk
status
[P]REV_INUSE
IS_[M]MAPPED
NON_MAIN_[A]RENA
Shared withprevious chunk
Glibc malloc Chunk
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
(prev_size)
size
fd
bk
(not used)
bins[n-1]
bins[n]
bins[n+1]
FD
BK
図2. small binのfree list
bins
c
struct malloc_chunk
PMA
Glibc malloc Bin
Glibc malloc Consolidating Chunks
メモリ確保と解放を繰り返しているとフラグメント化を起こしてしまう そこで, free()されるchunkと隣接するfree chunkの結合を考える.
自身の直前のchunkと隣接している.
自身の直後のchunkと隣接している.
PREV_INUSE bit 自身の直前に隣接するchunkが使用中か否かを判断するためのフラグ.
これが結合の際の判断基準となる.
Glibc malloc Consolidating Chunks
Chunkの結合処理はどこにある? Glibcを読む.
free(p)
__libc_free(p)
_int_free(av, p, have_lock) <- これ!
(a) 始点図3 _int_free()
(b) 結合箇所図3 _int_free()
(c) 終点図3 _int_free()
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
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
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
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))"
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が存在する.
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)
(prev_size)
size
data
(prev_size)
size
data+
pads
1
(b) Overflow図5 House of Einherjarの原理
Overflown
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
House of Einherjar Flaw / Flow
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)
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)
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は何回か編集可能であると仮定する.
House of Einherjar Evaluation
メリット メモリレイアウトにも依るがOff-by-oneなOverflowさえあればできる.
"House of Force"のような巨大なmalloc()を必要としない.
デメリット fake chunkを置ける領域の近くしかmalloc()で取得できない.
2つのアドレスのleakが必要となる.
評価: "悪くはない"
House of Einherjar Countermeasures
"struct malloc_chunk"がよくないのでは? そもそも"chunk->prev_size"が通常の書き込みにより上書きされることがよくない.
そもそもBoundary Tagアルゴリズムだから仕方がない.
対策方法は? Address checking
結合後の新しいchunkのアドレスは正しいか?
StackとHeapのアドレスは全然違う.
Return addressは守れる.
Heap内でのHouse of Einherjarには対応しきれない.
Thank You For Your Attention!Any Questions?