...
Excuse the ads! We need some help to keep our site up.
Include Page 00.Notice 00.Notice
List
Table of Contents outline true exclude List
Conditions
- 해당 기술은 다음과 같은 조건에서 동작합니다.
- 공격자에 의해 동일한 크기의 Fast chunk의 할당과 해제가 자유로워야 합니다.
- 공격자에 의해 해제된 Fast chunk를 한번더 해제 할 수 있어야 합니다.(Double free bug)
Exploit plan
- 다음과 같은 방법으로 공격할 수 있습니다.
- 동일한 크기의 Fast chunk 3개를 생성합니다.
- 첫번재 Fast chunk를 해제 합니다.
- 두번째 Fast chunk를 해제 합니다.
해제된 첫번재 Fast chunk를 다시 한번 해제 합니다.
- 공격 대상 영역과 같은 크기의 Heap 을 3개 할당 합니다.
- 첫번재 Heap 영역과 세번째 Heap 영역의 주소가 같습니다.
Example
Files
Panel |
---|
Source code
Fastbin duplicate
- "Fastbin duplicate"는 fastbin에 배치된 리스트를 악용한 공격입니다.
애플리케이션이 fastbin에 포함되는 메모리들을 중복으로 해제를 요청할 경우 할당자는 해당 chunk들을 list에 중복으로 배치됩니다.
중복으로 등록된 chunk와 동일한 크기의 메모리 할당을 여러번 요청하면, 할당자는 해당 chunk의 포인터를 중복으로 리턴합니다.
- 이러한 악용은 fastbin에서만 가능합니다.
- 예를 들어 malloc()에 크기가 112byte인 메모리의 할당을 3번 요청합니다.
- 애플리케이션이 첫번째 메모리의 포인터를 인수로 free()를 호출하면 할당자는 해당 chunk를 fastbin[6]에 배치합니다.
- 그리고 애플리케이션이 두번째 메모리를 해제를 요청하면 할당자는 fastbin[6]에 배치된 chunk의 fd에 해당 chunk를 배치합니다.
- 이미 해제된 첫번째 메모리를 다시 해제를 요청하면 해당 chunk가 fastbin[6]의 list 마지막에 배치됩니다.
- 즉, Fastbin[6]의 list는 "첫번째 메모리(0x602000) --> 두번째 메모리(0x602080) --> 첫번째 메모리(0x602000) --> ..." 와 같은 형태가 됩니다.
- 애플리케이션이 malloc()에 해제된 메모리와 같은 크기의 메모리의 할당을 요청합니다.
- 첫번째 요청에서는 Fastbin에 마지막에 배치된 메모리가 재할당합니다.
- 두번째 요청에서는 그 다음 메모리가 재할당됩니다.
- 세번째 요청에서 첫번째 요청에서 할당받은 메모리와 동일한 메모리가 할당됩니다.
- 즉 애플리케이션은 첫번째 메모리와 세번째 메모리의 포인터는 서로 같은 포인터입니다.
Panel | ||
---|---|---|
| ||
Example
- 다음 코드는 malloc()에게 크기가 112byte인 메모리 할당을 3번 요청합니다.
- 이 코드는 buf1,buf2 해제를 free()에 요청하고, buf1 해제를 다시 요청합니다.
- 그리고 다시 크기가 112byte인 메모리 할당을 malloc()에 3번 요청합니다.
Code Block | ||||
---|---|---|---|---|
| ||||
Code Block | ||||
| ||||
#include <stdio.h> #include <stdlib.h> int main() { int *buf1 = malloc(112); int *buf2 = malloc(112); int *buf3 = malloc(112); free(buf1); free(buf2); free(buf1); int *buf4 = malloc(112); int *buf5 = malloc(112); int *buf6 = malloc(112); } |
Exploit flow
Panel | ||
---|---|---|
| ||
Debugging
- 다음과 같이 Break point를 설정합니다.
0x4005b6 : 1번째 free() 함수 호출
0x4005c2 : 2번째 free() 함수 호출
0x4005ce : 3번째 free() 함수 호출
0x4005dd : 4번째 malloc() 함수 호출
0x4005eb : 5번째 malloc() 함수 호출
0x4005f9 : 6번째 malloc() 함수 호출
Code Block |
---|
gdb-peda$ b *0x00000000004005b6
Breakpoint 1 at 0x4005b6
gdb-peda$ b *0x00000000004005c2
Breakpoint 2 at 0x4005c2
gdb-peda$ b *0x00000000004005ce
Breakpoint 3 at 0x4005ce
gdb-peda$ b *0x00000000004005dd
Breakpoint 4 at 0x4005dd
gdb-peda$ b *0x00000000004005eb
Breakpoint 5 at 0x4005eb
gdb-peda$ b *0x00000000004005f9
Breakpoint 6 at 0x4005f9
gdb-peda$ |
- 다음과 같이 할당된 Heap 영역을 확인 할 수 있습니다.
- free() 함수 호출 전에 fastbinsY에 등록된 Chunk가 없습니다.
- 첫번째 free() 함수 호출 후에 fastbinsY에 0x602000 영역이 등록됩니다.
Code Block | ||
---|---|---|
| ||
gdb-peda$ r
Starting program: /home/lazenca0x0/Documents/def/fastbin_dup
Breakpoint 1, 0x00000000004005b6 in main ()
gdb-peda$ x/50gx 0x602000
0x602000: 0x0000000000000000 0x0000000000000081
0x602010: 0x0000000000000000 0x0000000000000000
0x602020: 0x0000000000000000 0x0000000000000000
0x602030: 0x0000000000000000 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000000
0x602050: 0x0000000000000000 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000000000
0x602070: 0x0000000000000000 0x0000000000000000
0x602080: 0x0000000000000000 0x0000000000000081
0x602090: 0x0000000000000000 0x0000000000000000
0x6020a0: 0x0000000000000000 0x0000000000000000
0x6020b0: 0x0000000000000000 0x0000000000000000
0x6020c0: 0x0000000000000000 0x0000000000000000
0x6020d0: 0x0000000000000000 0x0000000000000000
0x6020e0: 0x0000000000000000 0x0000000000000000
0x6020f0: 0x0000000000000000 0x0000000000000000
0x602100: 0x0000000000000000 0x0000000000000081
0x602110: 0x0000000000000000 0x0000000000000000
0x602120: 0x0000000000000000 0x0000000000000000
0x602130: 0x0000000000000000 0x0000000000000000
0x602140: 0x0000000000000000 0x0000000000000000
0x602150: 0x0000000000000000 0x0000000000000000
0x602160: 0x0000000000000000 0x0000000000000000
0x602170: 0x0000000000000000 0x0000000000000000
0x602180: 0x0000000000000000 0x0000000000020e81
gdb-peda$ p main_arena.fastbinsY
$1 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}
gdb-peda$ ni
0x00000000004005bb in main ()
gdb-peda$ p main_arena.fastbinsY
$2 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x602000, 0x0, 0x0, 0x0}
gdb-peda$ |
- 다음과 같이 해제된 2번째 Heap 영역이 fastbinsY에 등록되었습니다.
- fastbinsY 영역에는 최근에 해제된 heap영역이 등록됩니다.
- 2번째 해제된 Heap 영역에 free chunk가 생성됩니다.
- fd 영역에 이전에 해제된 free chunk의 주소가 저장됩니다.
- fastbinsY 영역에는 최근에 해제된 heap영역이 등록됩니다.
0x4005b7에서 fastbin에 배치된 메모리가 또 배치되는 것을 확인합니다.
0x4005c6, 0x4005d4, 0x4005e2에서는 malloc()에서 반환된 pointer를 확인합니다.
Code Block | ||
---|---|---|
| ||
lazenca0x0@ubuntu:~/Book/2.fast_dup$ gcc -o fast_dup fast_dup.c
lazenca0x0@ubuntu:~/Book/2.fast_dup$ gdb -q ./fast_dup
Reading symbols from ./fast_dup...(no debugging symbols found)...done.
gdb-peda$ disassemble main
Dump of assembler code for function main:
0x0000000000400566 <+0>: push rbp
0x0000000000400567 <+1>: mov rbp,rsp
0x000000000040056a <+4>: sub rsp,0x30
0x000000000040056e <+8>: mov edi,0x70
0x0000000000400573 <+13>: call 0x400450 <malloc@plt>
0x0000000000400578 <+18>: mov QWORD PTR [rbp-0x30],rax
0x000000000040057c <+22>: mov edi,0x70
0x0000000000400581 <+27>: call 0x400450 <malloc@plt>
0x0000000000400586 <+32>: mov QWORD PTR [rbp-0x28],rax
0x000000000040058a <+36>: mov edi,0x70
0x000000000040058f <+41>: call 0x400450 <malloc@plt>
0x0000000000400594 <+46>: mov QWORD PTR [rbp-0x20],rax
0x0000000000400598 <+50>: mov rax,QWORD PTR [rbp-0x30]
0x000000000040059c <+54>: mov rdi,rax
0x000000000040059f <+57>: call 0x400430 <free@plt>
0x00000000004005a4 <+62>: mov rax,QWORD PTR [rbp-0x28]
0x00000000004005a8 <+66>: mov rdi,rax
0x00000000004005ab <+69>: call 0x400430 <free@plt>
0x00000000004005b0 <+74>: mov rax,QWORD PTR [rbp-0x30]
0x00000000004005b4 <+78>: mov rdi,rax
0x00000000004005b7 <+81>: call 0x400430 <free@plt>
0x00000000004005bc <+86>: mov edi,0x70
0x00000000004005c1 <+91>: call 0x400450 <malloc@plt>
0x00000000004005c6 <+96>: mov QWORD PTR [rbp-0x18],rax
0x00000000004005ca <+100>: mov edi,0x70
0x00000000004005cf <+105>: call 0x400450 <malloc@plt>
0x00000000004005d4 <+110>: mov QWORD PTR [rbp-0x10],rax
0x00000000004005d8 <+114>: mov edi,0x70
0x00000000004005dd <+119>: call 0x400450 <malloc@plt>
0x00000000004005e2 <+124>: mov QWORD PTR [rbp-0x8],rax
0x00000000004005e6 <+128>: mov eax,0x0
0x00000000004005eb <+133>: leave
0x00000000004005ec <+134>: ret
End of assembler dump.
gdb-peda$ b *0x00000000004005b7
Breakpoint 1 at 0x4005b7
gdb-peda$ b *0x00000000004005c6
Breakpoint 2 at 0x4005c6
gdb-peda$ b *0x4005d4
Breakpoint 3 at 0x4005d4
gdb-peda$ b *0x00000000004005e2
Breakpoint 4 at 0x4005e2
gdb-peda$ |
- fastbins[6]의 상단에는 마지막에 해제된 메모리(0x602080)가 배치되어 있습니다..
- 해당 chunk의 fd에 앞에서 해제된 메모리의 pointer(0x602000)가 배치되어있습니다.
- fastbin의 list는 0x602080 --> 0x602000입니다.
- buf1(0x602000)이 해제가 되면 fastbins[6]의 상단에 buf1(0x602000)이 배치됩니다.
- fastbin의 list는 0x602000 --> 0x602080 --> 0x602000가 됩니다.
- 이제 fastbin_dup 구현이 가능해졌습니다.
Code Block | ||
---|---|---|
gdb-peda$ r
Starting program: /home/lazenca0x0/Book/2.fast_dup/fast_dup
Breakpoint 1, 0x00000000004005b7 in main () | ||
Code Block | ||
| ||
gdb-peda$ c Continuing. Breakpoint 2, 0x00000000004005c2 in main () gdb-peda$ ni gdb-peda$ p main_arena.fastbinsY [6] $4$1 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x602080, 0x0, 0x0, 0x0} (mfastbinptr) 0x602080 gdb-peda$ x/50gx 0x602000 0x602000: 0x0000000000000000 0x0000000000000081 0x602010: 0x0000000000000000 0x0000000000000000 0x602020: 0x0000000000000000 0x0000000000000000 0x602030: 0x0000000000000000 0x0000000000000000 0x602040: 0x0000000000000000 0x0000000000000000 0x602050: 0x0000000000000000 0x0000000000000000 0x602060: 0x0000000000000000 0x0000000000000000 0x602070: 0x0000000000000000 0x00000000000000004gx 0x602080 0x602080: 0x0000000000000000 0x0000000000000081 0x602090: 0x0000000000602000 0x0000000000000000 0x6020a0: 0x0000000000000000 0x0000000000000000 0x6020b0: 0x0000000000000000 0x0000000000000000 0x6020c0: 0x0000000000000000 0x0000000000000000 0x6020d0: 0x0000000000000000 0x0000000000000000 0x6020e0: 0x0000000000000000 0x0000000000000000 0x6020f0: 0x0000000000000000 0x0000000000000000 0x602100gdb-peda$ x/4gx 0x0000000000602000 0x602000: 0x0000000000000000 0x0000000000000081 0x602110: 0x0000000000000000 0x0000000000000000 0x602120: 0x0000000000000000 0x0000000000000000 0x602130: 0x0000000000000000 0x0000000000000000 0x6021400x602010: 0x0000000000000000 0x0000000000000000 0x602150: 0x0000000000000000 0x0000000000000000 0x602160: 0x0000000000000000 0x0000000000000000 0x602170: 0x0000000000000000 0x0000000000000000 0x602180: 0x0000000000000000 0x0000000000020e81 gdb-peda$ |
- 다음과 같이 해제되었던 Chunk가 fastbinsY에 등록되었습니다.
- 해제된 heap 영역을 다시 해제가 가능합니다.
- 해제되었던 영역이 fastbinsY에 정상적으로 등록됩니다.
- 그리고 해당 Free chunk의 fd 영역에 2번재 Free chunk의 주소가 저장됩니다.
Code Block | ||
---|---|---|
| ||
gdb-peda$ c Continuing. Breakpoint 3, 0x00000000004005ceni 0x00000000004005bc in main () gdb-peda$ ni 0x00000000004005d3 in main ()x/4gx 0x0000000000602000 0x602000: 0x0000000000000000 0x0000000000000081 0x602010: 0x0000000000602080 0x0000000000000000 gdb-peda$ p main_arena.fastbinsY [6] $5$2 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x602000, 0x0, 0x0, 0x0} gdb-peda$ x/50gx 0x602000 0x602000: 0x0000000000000000 0x0000000000000081 0x602010: 0x0000000000602080 0x0000000000000000 0x602020: 0x0000000000000000 0x0000000000000000 0x602030: 0x0000000000000000 0x0000000000000000 0x602040: 0x0000000000000000 0x0000000000000000 0x602050: 0x0000000000000000 0x0000000000000000 0x602060: 0x0000000000000000 0x0000000000000000 0x602070: 0x0000000000000000 0x0000000000000000 0x602080: 0x0000000000000000 0x0000000000000081 0x602090: 0x0000000000602000 0x0000000000000000 0x6020a0: 0x0000000000000000 0x0000000000000000 0x6020b0: 0x0000000000000000 0x0000000000000000 0x6020c0: 0x0000000000000000 0x0000000000000000 0x6020d0: 0x0000000000000000 0x0000000000000000 0x6020e0: 0x0000000000000000 0x0000000000000000 0x6020f0: 0x0000000000000000 0x0000000000000000 0x602100: 0x0000000000000000 0x0000000000000081 0x602110: 0x0000000000000000 0x0000000000000000 0x602120: 0x0000000000000000 0x0000000000000000 0x602130: 0x0000000000000000 0x0000000000000000 0x602140: 0x0000000000000000 0x0000000000000000 0x602150: 0x0000000000000000 0x0000000000000000 0x602160: 0x0000000000000000 0x0000000000000000 0x602170: 0x0000000000000000 0x0000000000000000 0x602180: 0x0000000000000000 0x0000000000020e81 (mfastbinptr) 0x602000 gdb-peda$ |
- 다음과 같이 Heap 영역을 할당 받습니다.4번째
malloc(
112) : 0x602010 - 5번째 malloc(112) : 0x602090
- 6번째 malloc(112) : 0x602010
- fastbinsY의 변화
0x602000 → 0x602080 → 0x602000 → 0x602080
- malloc()함수는 fastbinsY에 동일한 크기의 free chunk가 존재하기 때문에 fastbinsY에 등록되어 있는 heap 영역을 재할당 합니다.
- 이러한 현상이 발생하는 이유는 다음과 같습니다.
- fastbins은 free chunk를 Single list로 관리하고 있습니다.
- 동일한 크기의 fast chunk가 여러 개가 해제되면, chunk header의 fd 영역을 이용해 관리합니다.
- 즉, 해당 현상이 발생하는 이유는 Double free로 인해 buf1과 buf2 free chunk의 fd 값이 상대 chunk를 가리키고 있기 때문입니다.
- fastbins은 free chunk를 Single list로 관리하고 있습니다.
)에 112byte를 요청하면 fastbinsY[6]의 상단에 있는 메모리(0x602010)가 재할당됩니다.
fastbinsY[6]의 상단에는 다음 메모리(0x602080)가 배치됩니다.
마지막 요청에서는 첫 재할당된 메모리(0x602010)와 같은 메모리(0x602010)가 재할당됩니다.
Code Block | ||
---|---|---|
| ||
Code Block | ||
| ||
gdb-peda$ c Continuing. Breakpoint 42, 0x00000000004005dd0x00000000004005c6 in main () gdb-peda$ i r rax rax 0x602010 0x602010 gdb-peda$ p main_arena.fastbinsY [6] $6$3 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x602080, 0x0, 0x0, 0x0} (mfastbinptr) 0x602080 gdb-peda$ c Continuing. Breakpoint 53, 0x00000000004005eb0x00000000004005d4 in main () gdb-peda$ i r rax rax 0x602090 0x602090p main_arena.fastbinsY[6] $5 = (mfastbinptr) 0x602000 gdb-peda$ p main_arena.fastbinsY $7 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x602000, 0x0, 0x0, 0x0} i r rax rax 0x602090 0x602090 gdb-peda$ c Continuing. Breakpoint 64, 0x00000000004005f90x00000000004005e2 in main () gdb-peda$ i r rax rax 0x602010 0x602010 gdb-peda$ p main_arena.fastbinsY [6] $8$4 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x602080, 0x0, 0x0, 0x0}(mfastbinptr) 0x602080 gdb-peda$ |
Related information
...