gef➤ heap bins
──────────────────────────────────────────────── Tcachebins for thread 1 ────────────────────────────────────────────────
Tcachebins[idx=8, size=0xa0] count=5 ← Chunk(addr=0x405700, size=0xa0, flags=PREV_INUSE) ← Chunk(addr=0x405660, size=0xa0, flags=PREV_INUSE) ← Chunk(addr=0x4055c0, size=0xa0, flags=PREV_INUSE) ← Chunk(addr=0x405520, size=0xa0, flags=PREV_INUSE) ← Chunk(addr=0x405480, size=0xa0, flags=! PREV_INUSE)
─────────────────────────────────────────── Fastbins for arena 0x7ffff7fa9b80 ───────────────────────────────────────────
Fastbins[idx=0, size=0x20] 0x00
Fastbins[idx=1, size=0x30] 0x00
Fastbins[idx=2, size=0x40] 0x00
Fastbins[idx=3, size=0x50] 0x00
Fastbins[idx=4, size=0x60] 0x00
Fastbins[idx=5, size=0x70] 0x00
Fastbins[idx=6, size=0x80] 0x00
────────────────────────────────────────── Unsorted Bin for arena 'main_arena' ──────────────────────────────────────────
[+] Found 0 chunks in unsorted bin.
─────────────────────────────────────────── Small Bins for arena 'main_arena' ───────────────────────────────────────────
[+] small_bins[9]: fw=0x4053d0, bk=0x405290
→ Chunk(addr=0x4053e0, size=0xa0, flags=PREV_INUSE) → Chunk(addr=0x4052a0, size=0xa0, flags=PREV_INUSE)
[+] Found 2 chunks in 1 small non-empty bins.
─────────────────────────────────────────── Large Bins for arena 'main_arena' ───────────────────────────────────────────
[+] Found 0 chunks in 0 large non-empty bins.
gef➤ 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: 0x4058e0 (size : 0x20720)
last_remainder: 0x0 (size : 0x0)
unsortbin: 0x0
(0x0a0) smallbin[ 8]: 0x4053d0 (doubly linked list corruption 0x4053d0 != 0x0 and 0x4053d0 is broken)
(0xa0) tcache_entry[8](5): 0x405700 --> 0x405660 --> 0x4055c0 --> 0x405520 --> 0x405480
그리고 Finally we alloc a 0x90 chunk with calloc to trigger the attack. The small bin preiously freed will be returned to user, the other one and the fake_chunk were linked into tcache bins
Now our fake chunk has been put into tcache bin[0xa0] list. Its fd pointer now point to next free chunk: %p and the bck->fd has been changed into a libc addr: %p\n\n",(void*)stack_var[2],(void*)stack_var[4]
tcache_stashing_unlink_attack
요약
- calloc의 취약점?을 이용하여 공격
- calloc은 할당했을때 tcache bin에서 chunk를 가져가지 않는다.
- calloc은 여러 bin들을 탐색하고, 대응하는 size의 bin이 tcache bin에 비어있지 않다면 이러한 bin을 사용
0x90 크기의 청크를 9개를 할당
index 3~8까지 free, 총 6개의 tcache bin에 chunk가 들어감을 확인하였음
다음 index 1의 chunk를 해제 -> 총 tcache bin은 7개로 꽉 차게 됨
index 0의 chunk를 해제 -> tcache bin은 꽉 차고, 크기는 0x90(144)이기 때문에 unsorted bin에 들어가게 됨
index 2 해제, index 0과 2가 서로 가리킴
아까 처음에 할당했던 0x90보다 큰 size인 0xa0을 할당 -> small bin에 들어가게 됨
0x90사이즈의 청크를 재할당, tcache_entry의 번호가 하나 줄어듬
한번 더 0x90사이즈의 chunk 할당 -> 총 5개의 tcache bin과 2개의 smallbin이 존재
victem->bk의 포인터 주소를 fake_chunk의 주소로 덮는다
그리고 Finally we alloc a 0x90 chunk with calloc to trigger the attack. The small bin preiously freed will be returned to user, the other one and the fake_chunk were linked into tcache bins
Now our fake chunk has been put into tcache bin[0xa0] list. Its fd pointer now point to next free chunk: %p and the bck->fd has been changed into a libc addr: %p\n\n",(void*)stack_var[2],(void*)stack_var[4]
printf("As you can see, next malloc(0x90) will return the region our fake chunk: %p\n",(void*)target);