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 = {0x224a6b0, 0x224a6d0, 0x224a700, 0x224a740, 0x0 <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 = {0x78c6d0, 0x78c720, 0x78c790, 0x78c820, 0x0 <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 = {0x23956b0, 0x0 <repeats 63 times>} } |
이 상태에서 같은 크기로 malloc을 2번 실행하면 같은 주소에 위치한 chunk를 두 번 할당받게 된다.
'Pwn_Others > Concepts' 카테고리의 다른 글
[glibc] ptmalloc2 (0) | 2020.04.13 |
---|---|
[glibc] struct _IO_FILE (0) | 2020.01.17 |