본문으로 바로가기

[glibc] tcache

category Pwn_Others/Concepts 2020. 4. 24. 22:40

malloc.c 분석 포스트에 모든 내용을 담기 어려울 것 같아서 내용을 분리했다.

tcache는 libc의 전역변수가 아니라 heap에 malloc으로 공간을 할당받은 구조체에서 관리한다. (malloc.c 분석 참고)

 

tcache

malloc(0x10) 부터 malloc(0x40) 까지 호출하고, 각 chunk를 모두 free하면 아래와 같이 tcache의 count와 entries 필드에 정보가 추가된 것을 볼 수 있다.

 

Initialize stdio heap space

malloc: 0x224a6b0 (size = 0x20)
malloc: 0x224a6d0 (size = 0x30)
malloc: 0x224a700 (size = 0x40)
malloc: 0x224a740 (size = 0x50)
free: 0x224a6b0 (size = 0x20)
free: 0x224a6d0 (size = 0x30)
free: 0x224a700 (size = 0x40)
free: 0x224a740 (size = 0x50)

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
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x224a780 (size : 0x20880)
       last_remainder: 0x0 (size : 0x0)
            unsortbin: 0x0
(0x20)   tcache_entry[0](1): 0x224a6b0
(0x30)   tcache_entry[1](1): 0x224a6d0
(0x40)   tcache_entry[2](1): 0x224a700
(0x50)   tcache_entry[3](1): 0x224a740
gdb-peda$ p *(struct malloc_chunk *)0x224a6a0
$1 = {
  mchunk_prev_size = 0x0,
  mchunk_size = 0x21,
  fd = 0x0,
  bk = 0x224a010,
  fd_nextsize = 0x0,
  bk_nextsize = 0x31
}
gdb-peda$ p *(tcache_entry *)0x224a6b0
$2 = {
  next = 0x0,
  key = 0x224a010
}
gdb-peda$ p *(tcache_perthread_struct *)0x224a010
$3 = {
  counts = {0x1, 0x1, 0x1, 0x1, 0x0 <repeats 60 times>},
  entries = {0x224a6b00x224a6d00x224a7000x224a7400x0 <repeats 60 times>}
}

 

다음으로 각 크기의 chunk를 2개 할당하고 free 했을 때의 상황을 살펴본다.

 

Initialize stdio heap space

malloc: 0x78c6b0 (size = 0x20)
malloc: 0x78c6d0 (size = 0x20)
malloc: 0x78c6f0 (size = 0x30)
malloc: 0x78c720 (size = 0x30)
malloc: 0x78c750 (size = 0x40)
malloc: 0x78c790 (size = 0x40)
malloc: 0x78c7d0 (size = 0x50)
malloc: 0x78c820 (size = 0x50)
free: 0x78c6b0 (size = 0x20)
free: 0x78c6d0 (size = 0x20)
free: 0x78c6f0 (size = 0x30)
free: 0x78c720 (size = 0x30)
free: 0x78c750 (size = 0x40)
free: 0x78c790 (size = 0x40)
free: 0x78c7d0 (size = 0x50)
free: 0x78c820 (size = 0x50)

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
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x78c860 (size : 0x207a0) 
       last_remainder: 0x0 (size : 0x0)
            unsortbin: 0x0
(0x20)   tcache_entry[0](2): 0x78c6d0 --> 0x78c6b0
(0x30)   tcache_entry[1](2): 0x78c720 --> 0x78c6f0
(0x40)   tcache_entry[2](2): 0x78c790 --> 0x78c750
(0x50)   tcache_entry[3](2): 0x78c820 --> 0x78c7d0
gdb-peda$ p *(struct malloc_chunk *)0x78c6c0
$1 = {
  mchunk_prev_size = 0x0,
  mchunk_size = 0x21,
  fd = 0x78c6b0,
  bk = 0x78c010,
  fd_nextsize = 0x0,
  bk_nextsize = 0x31
}
gdb-peda$ p *(tcache_entry *)0x78c6d0
$2 = {
  next = 0x78c6b0,
  key = 0x78c010
}
gdb-peda$ p *(tcache_perthread_struct *)0x78c010
$3 = {
  counts = {0x2, 0x2, 0x2, 0x2, 0x0 <repeats 60 times>},
  entries = {0x78c6d00x78c7200x78c7900x78c8200x0 <repeats 60 times>}
}

 

entry의 next 필드의 값이 이전에 free된 chunk 값을 가리키고 있다.

 

Double free

0x20 크기의 chunk를 1개 할당한 뒤 해당 chunk를 2번 free하면, double free를 탐지하고 SIGABRT를 발생시킨다.

 

Initialize stdio heap space

malloc: 0xf806b0 (size = 0x20)
free: 0xf806b0 (size = 0x20)
free(): double free detected in tcache 2

Stopped reason: SIGABRT
__GI_raise (sig=sig@entry=0x6) at ../sysdeps/unix/sysv/linux/raise.c:50
50    ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.

 

이는 entry의 key 필드값이 tcache와 같기 때문이다. 이 글의 _int_free 분석 내용을 참고하자.

첫 번째 free 이후, key 필드의 값을 다른 값으로 변조시킨 뒤 실행한 결과는 아래와 같다.

 

Initialize stdio heap space

malloc: 0x23956b0 (size = 0x20)
free: 0x23956b0 (size = 0x20)
free: 0x23956b0 (size = 0x20)

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
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x23956c0 (size : 0x20940)
       last_remainder: 0x0 (size : 0x0)
            unsortbin: 0x0
(0x20)   tcache_entry[0](2): 0x23956b0 --> 0x23956b0 (overlap chunk with 0x23956a0(freed) )
gdb-peda$ p *(tcache_entry *)0x23956b0
$1 = {
  next = 0x23956b0,
  key = 0x2395010
}
gdb-peda$ p *(tcache_perthread_struct *)0x2395010
$2 = {
  counts = {0x2, 0x0 <repeats 63 times>},
  entries = {0x23956b00x0 <repeats 63 times>}
}

 

이 상태에서 같은 크기로 malloc을 2번 실행하면 같은 주소에 위치한 chunk를 두 번 할당받게 된다.

'Pwn_Others > Concepts' 카테고리의 다른 글

[glibc] ptmalloc2  (0) 2020.04.13
[glibc] struct _IO_FILE  (0) 2020.01.17