#dokydoky

[Heap Exploitation] Fastbin attack 본문

System Hacking

[Heap Exploitation] Fastbin attack

dokydoky 2017. 8. 9. 15:54

Reference

Overview

Fastbin

arena(malloc_state)
gdb-peda$ p main_arena
$1 = {
  mutex = 0x0,
  flags = 0x0,
  fastbinsY = {0x00x00x00x00x00x00x00x00x00x0},  // mfastbinptr fastbinsY[NFASTBINS]; // NFASTBINS = 10
                                                                   // fastbin은 arena별로 10가지 크기의 list 존재 -> 하지만 실제로 7개만 사용하는 듯.
  top = 0x0,
  last_remainder = 0x0,
  bins = {0x0 <repeats 254 times>},
  binmap = {0x00x00x00x0},
  next = 0x7ffff7dd1b20 <main_arena>,
  next_free = 0x0,
  attached_threads = 0x1,
  system_mem = 0x0,
  max_system_mem = 0x0
}

 

32bit machine

  • min size(metadata 포함) : 0x10 (header: 0x8, data: 0x8)
  • max size : 0x40 (header: 0x8, data = 0x38)
  • alignment size : 0x8
32bit fastbin
gdb-peda$ heapinfo
(0x10)     fastbin[0]: 0x0
(0x18)     fastbin[1]: 0x0
(0x20)     fastbin[2]: 0x0
(0x28)     fastbin[3]: 0x0
(0x30)     fastbin[4]: 0x0
(0x38)     fastbin[5]: 0x0
(0x40)     fastbin[6]: 0x0

 

64bit machine

  • min size : 0x20 (header: 0x10, data: 0x10)
  • max size : 0x80 (header: 0x10, data: 0x70)
  • alignment size : 0x10
64bit fastbin
gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0

 

Attacks

Double Free

공격개요

fastbin size의 chunk를 double free하여, malloc을 여러번 호출했을 때 동일한 주소를 2번 반환 받을 수 있다.

ex)
free(a) // size=10
free(b)
free(a)
 
 
malloc(10// a
malloc(10// b
malloc(10// a

 

제약조건

  • fastbin의 top에 있는 chunk와 free하는 chunk가 같으면, double free corruption.
free - fastbin check
if NOT) minumum <= next chunk's size <= maximum(av->system_mem)
    error ("free(): invalid next size (fast)")
if) the chunk at the top == the chunk we are going to add
    error ("double free or corruption (fasttop)")
if NOT) the size of the chunk at the top == the size of the chunk we are adding.
    error ("invalid fastbin entry (free)")
Insert the chunk at the top of the fastbin list and return.

 

Forging chunks

공격개요

fastbin size의 chunk가 free되고 fastbin에 들어간 뒤, 해당 free된 chunk의 fd의 값의 조작이 가능하다면 malloc의 결과로 원하는 주소를 리턴받을 수 있다.

(fastbin뿐만 아니라, 다른 binlist에도 적용되는 내용.)

제약조건

단, malloc 함수내에서 아래와 같이, 요청한 크기와 fastbin에서 꺼낸 chunk의 크기가 같은 것을 확인하므로, fakechunk.size를 chunk.size와 동일하게 설정해줘야 한다. 

malloc - fastchunk size check
3383           if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0))                 
3384             {
3385               errstr = "malloc(): memory corruption (fast)";                                   
3386             errout:
3387               malloc_printerr (check_action, errstr, chunk2mem (victim), av);                  
3388               return NULL;
3389             }

 

House of spirit

공격개요

free되기 전에 free되는포인터(ptr)를 조작하여 binlist에 fake chunk을 넣을 수 있는 방법.
다른 binlist들도 가능하나, fastbin이 선호됨.

제약조건

fakechunk.size : fastbin range (fastbin을 이용할 경우)
fakechunk's next chunk's size : >2*SIZE_SZ  AND < av→system_mem(128kb by default for the main arena)

free pseudo-code
if NOT) p is before p+chunksize(p)
    error ("free(): invalid pointer")
  
if NOT) chunk >= MINSIZE OR multiple of MALLOC_ALIGNMENT // chunk.size를 해당 범위로 설정해줘야 함
    error ("free(): invalid size")
   
if) chunk's size == fastbin range // chunk.size를 fastbin 크기로 설정해줘야 이 구문이 실행
    if NOT) minumum <= next chunk's size <= maximum(av->system_mem) // nextchunk.size를 해당 범위로 설정
        error ("free(): invalid next size (fast)")
    if) the chunk at the top == the chunk we are going to add
        error ("double free or corruption (fasttop)")
    if NOT) the size of the chunk at the top == the size of the chunk we are adding.
        error ("invalid fastbin entry (free)")
    Insert the chunk at the top of the fastbin list and return.
  
if) chunk is not mmapped
    if) the chunk == top chunk
        error ("double free or corruption (top)")
    if NOT) next chunk is within the boundaries of the arena
        error ("double free or corruption (out)")
    if NOT) next chunk's PREVIOUS_IN_USE bit is marked
        error ("double free or corruption (!prev)")
    if NOT) minumum <= next chunk's size <= maximum(av->system_mem)
        error ("free(): invalid next size (normal)")
   
    if) previous chunk is not in use
        unlink(previous chunk)
    if) next chunk != top chunk
        if) next chunk is not in use
            unlink(next chunk)
        Merge the chunk with previous or next, if free
        if NOT) unsorted_chunks(av)->fd->bk == unsorted_chunks(av)
            error ("free(): corrupted unsorted chunks")
        Add it to the head of unsorted bin
    else// not top chunk
        Merge the chunk into a single top chunk
   
else)
    call munmap_chunk

 



Comments