fastbin_dup.c
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 | #include <stdio.h> #include <stdlib.h> int main() { printf("This file demonstrates a simple double-free attack with fastbins.\n"); 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 ]. 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 |
위 소스코드는 double free bug에 대해서 설명하고 있다.
double free bug는 라이브러리 2.3.2 이하에서 발생한다.
그럼 하나씩 분석해보자.
우선 malloc()을 통해 a,b,c 포인터 변수에 각각 8 byte 크기만큼 할당해준다.
This file demonstrates a simple double-free attack with fastbins.
Allocating 3 buffers.
1st malloc(8): 0x804b410
2nd malloc(8): 0x804b420
3rd malloc(8): 0x804b430
할당된 주소는 위와 같이 a,b,c 순으로 0x804b410, 0x804b420, 0x804b430이다.
각각 0x8 크기만큼 할당했는데 왜 할당된 공간의 주소 차이는 0x16 씩 차이가 나는가?
그 이유는 malloc_chunk 구조체를 보면 알 수 있다.
struct malloc_chunk {
INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
struct malloc_chunk* fd; /* double links -- used only if free. */
struct malloc_chunk* bk;
/* Only used for large blocks: pointer to next larger size. */
struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
struct malloc_chunk* bk_nextsize;
};
prev_size |
size |
data |
prev_size |
size |
fd |
bk |
|
gdb를 통해 구조를 직접 확인하면 좀 더 이해하기가 쉽다.
다음은 free하기 전 a, b, c의 주소이다.
Breakpoint 1, 0x08048507 in main ()
(gdb) x/32wx 0x804b408
0x804b408: 0x00000000 0x00000011 0x00000000 0x00000000
0x804b418: 0x00000000 0x00000011 0x00000000 0x00000000
0x804b428: 0x00000000 0x00000011 0x00000000 0x00000000
0x804b438: 0x00000000 0x00020bc9 0x00000000 0x00000000
0x804b448: 0x00000000 0x00000000 0x00000000 0x00000000
0x804b458: 0x00000000 0x00000000 0x00000000 0x00000000
0x804b410이 a의 data 영역이므로, 0x804b408은 prev_size, 0x804b40c는 size인 것을 알 수 있다.
여기서 size가 0x10이 아닌 0x11인 이유는 병합이 이루어지지 않도록 하기 위해 PREV_INUSE 플래그가 설정되어있기 때문이다. 이와 마찬가지로 b, c 도 a와 비슷하게 할당되게 된다.
free(a)를 통해 먼저 a의 데이터가 삭제된다.
이전 chunk가 존재하지 않기 때문에 fd는 0이 된다.
0x08048550 in main ()
(gdb) x/32wx 0x804b408
0x804b408: 0x00000000 0x00000011 0x00000000 0x00000000
0x804b418: 0x00000000 0x00000011 0x00000000 0x00000000
0x804b428: 0x00000000 0x00000011 0x00000000 0x00000000
그 다음 주석처리 되어 있는 free(a)를 주석을 푼 뒤 프로그램을 실행시켜보았다.
그 결과 double-free 에러가 발생하였다.
This file demonstrates a simple double-free attack with fastbins.
Allocating 3 buffers.
1st malloc(8): 0x804b410
2nd malloc(8): 0x804b420
3rd malloc(8): 0x804b430
Freeing the first one...
If we free 0x804b410 again, things will crash because 0x804b410 is at the top of the free list.
*** Error in `./fastbin_dup2': double free or corruption (fasttop): 0x0804b410 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x67257)[0xb7e72257]
/lib/i386-linux-gnu/libc.so.6(+0x6d577)[0xb7e78577]
/lib/i386-linux-gnu/libc.so.6(+0x6dd31)[0xb7e78d31]
./fastbin_dup2[0x8048574]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf7)[0xb7e23637]
./fastbin_dup2[0x80483c1]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:01 941684 /root/pwn/fastbin_dup2
08049000-0804a000 r--p 00000000 08:01 941684 /root/pwn/fastbin_dup2
0804a000-0804b000 rw-p 00001000 08:01 941684 /root/pwn/fastbin_dup2
해당 에러가 발생하는 이유는 이미 한 번의 free(a)를 통해 a가 free list의 맨 위에 있는 상태에서 또 다시 free(a)가 이루어졌기 때문이다.
그렇기 때문에 다음과 같이 free를 해주어야 한다.
위의 경우 free(b)를 한 후에 free(a)를 하게 되므로 free list의 최상위가 a가 아닌 b가 되므로 a를 한 번 더 free 할 수 있게 된다.
1. free(a)
이전 chunk가 존재하지 않으므로 a의 fd는 0이 된다.
0x08048550 in main ()
1: x/3i $pc-5
0x804854b <main+176>: call 0x8048350 <free@plt>
=> 0x8048550 <main+181>: add esp,0x10
0x8048553 <main+184>: sub esp,0x4
2: x/12xw 0x804b408
0x804b408: 0x00000000 0x00000011 0x00000000 0x00000000
0x804b418: 0x00000000 0x00000011 0x00000000 0x00000000
0x804b428: 0x00000000 0x00000011 0x00000000 0x00000000
(gdb)
2. free(b)
chunk list에 이전에 free된 a가 존재하므로 a의 주소인 0x804b408이 b의 fd에 들어가게 된다.
0x08048587 in main ()
1: x/3i $pc-5
0x8048582 <main+231>: call 0x8048350 <free@plt>
=> 0x8048587 <main+236>: add esp,0x10
0x804858a <main+239>: sub esp,0x8
2: x/12xw 0x804b408
0x804b408: 0x00000000 0x00000011 0x00000000 0x00000000
0x804b418: 0x00000000 0x00000011 0x0804b408 0x00000000
0x804b428: 0x00000000 0x00000011 0x00000000 0x00000000
3. free(a)
chunk list의 최상위가 a가 아니기 때문에 한 번더 free(a)가 가능하다.
chunk list에 이전 chunk인 b가 존재하므로 b의 주소인 0x804b418이 a의 fd에 들어가게 된다.
Breakpoint 4, 0x080485a8 in main ()
1: x/3i $pc-5
0x80485a3 <main+264>: call 0x8048350 <free@plt>
=> 0x80485a8 <main+269>: add esp,0x10
0x80485ab <main+272>: sub esp,0xc
2: x/12xw 0x804b408
0x804b408: 0x00000000 0x00000011 0x0804b418 0x00000000
0x804b418: 0x00000000 0x00000011 0x0804b408 0x00000000
0x804b428: 0x00000000 0x00000011 0x00000000 0x00000000
프로그램 실행 결과
This file demonstrates a simple double-free attack with fastbins.
Allocating 3 buffers.
1st malloc(8): 0x804b410
2nd malloc(8): 0x804b420
3rd malloc(8): 0x804b430
Freeing the first one...
If we free 0x804b410 again, things will crash because 0x804b410 is at the top of the free list.
So, instead, we'll free 0x804b420.
Now, we can free 0x804b410 again, since it's not the head of the free list.
Now the free list has [ 0x804b410, 0x804b420, 0x804b410 ]. If we malloc 3 times, we'll get 0x804b410 twice!
1st malloc(8): 0x804b410
2nd malloc(8): 0x804b420
3rd malloc(8): 0x804b410
'System' 카테고리의 다른 글
qemu arm 실행 (0) | 2018.05.10 |
---|---|
[how2heap] fastbin_dup_into_stack (0) | 2018.02.18 |
[how2heap] first_fit (Use After Free) (0) | 2018.02.18 |
64 bit 환경에서의 ELF 파일 인자 전달 방식 (0) | 2017.11.05 |
Metasploit 이용한 쉘코드(Shellcode) 작성 (0) | 2016.11.12 |