[8] Use After Free / Double Free Bug

2017. 6. 16. 14:48SystemHacking/System




https://bpsecblog.wordpress.com/2016/10/06/heap_vuln/ 해당 블로그를 참고하였고, 해당 내용은 공부하기 편하도록 단지 정

리만 해놓은 문서입니다.

Heap영역은 컴파일러가 예측할 수 없는 프로그래머가 관리하는 영역입니다

동적할당으로 인해 컴파일 시기에 크기를 알 수 없는 데이터를 관리합니다

이전 Heap게시글에서는 Heap Overflow 를 공부했고, 이번에는 UAF와 DFB에 대해 알아보겠습니다



[ UAF ] ( Use After Free )

말그대로 free가 일어난 후에 발생하는 현상입니다

ex1.heap.c

 #include<stdio.h>

 #include<stdlib.h>

 int main(){

 int *heap1;

 int *heap2;

 int *heap3;


 heap1 = (int*)malloc(256);

 heap2 = (int*)malloc(256);


 printf( "heap1 : %p\n", hea1 );

 printf( "heap2 : %p\n", heap2);


 *heap2 = 1234;

 printf("heap2 number : %d\n", *heap2 );

 free(heap2);

 printf("free heap2\n");


 heap3= (int *)malloc(256);

 printf("new heap %p\n" , heap3 );

 printf("new heap number : %d\n",*heap3 );


 return 0;


[실행결과]

[ 그림1 ]

 

*heap2 가 free된 후 똑같은 크기의 heap3를 할당했더니 같은 주소에 할당되었다

힙의 할당은 효율적으로 하기위해 반환된 heap영역의 크기를 기억하고 같은 크기의 할당 요청이 들어오면 그 영역을 재사용한다

그리고 free를 한다고해서 해당영역의 값이 초기화 되는 것이 아닌 것을 알 수 있다 ( 1234 가 그대로 남아있음 )



ex2.UAF.c

#include<stdio.h>

#include<stdlib.h>

#inclde<string.h>

typedef struct{                          // test구조체 선언

 char name[10];

 void (*print)(void*);

} test;

typedef struct{                        // string 구조체 선언

 char name[128];

} string;

void printName( test* t){          // 함수 선언

 printf("%s \n", t->name);

}

void shell(void){                     // 함수 선언

printf("this is shell\n");

}

int main(){

 test* t1;

 string* s1;

 t1 = malloc(256);

 strcpy(t1->name,"DOG");

 t1->print = (void*)printName;

 t1->print(t1);                        // t1구조체의 name멤버변수에 저장된 DOG가 출력된다

 free(t1);                               // t1구조체 해제


 s1 = malloc(256);                  // 같은크기의 s1구조체에게 메모리 할당

 scanf("%128s",s1->name);       // s1구조체의 name멤버변수에 데이터 입력

 t1->print(t1);                        // 아래서 설명하겠습니다

 return 0;

}


test구조체에 메모리를 동적할당 한 후 함수포인터를 초기화 시키고 사용한 뒤 free로 해제하였고,

그리고 다시 string구조체를 동적할당 한 후 test구조체의 함수포인터를 다시 재사용하는 코드입니다


1> 256바이트의 메모리 공간은 test구조체에게 할당 해주었습니다

2> free로 해제하고 다시 256바이트의 메모리 공간을 string구조체에 할당하면 그 test구조체가 사용했던 영역을 재사용합니다

3> 그리고 scanf()함수로 인해 string구조체에서 데이터를 입력받습니다

4> 10byte를 입력받으면 test->name공간이였던 부분이 가득 차게되고 다음 공간은 함수형포인터 (*print)()의 공간이죠?

5> 해당 위치에 shell()함수의 주소를 입력시킵니다

6> 그럼 마지막 코드 " t1->print(t1) " 에서는 t1구조체에 대해서 실행하려하지만 실제로는 s1이 될것이고 함수형포인터 print()가 가리키고 있는 함수는 shell()함수입니다

이렇게 해제된 메모리를 재사용하는 경우를 UAF라고 합니다. 이렇게 우리는 프로세스의 실행방향을 바꿔놓을 수 있습니다




[ DFB ] Double Free Bug


제일 먼저 알아할 내용은 메모리공간을 할당할 때 할당된 영역의 크기는 요청한 사이즈보다 크다는 것입니다

아래 소스파일을 확인해보겠습니다

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

int main(){


 char *a,*b,*c;

 a=malloc(0x20);

 b=malloc(0x20);

 c=malloc(0x20);


 strcpy(a,"AAAAAAAA");

 strcpy(b,"BBBBBBBB");

 strcpy(c,"CCCCCCCC");


 printf("1st : %p\n",a);

 printf("2nd : %p\n, b);

 printf("3rd : %p\n, c);


 free(c);

 free(b);

 free(a);


 return 0;

}



실행결과

1st : 0x1ca3010

2nd : 0x1ca3040

3rd : 0x1ca3070 


malloc()으로 할당한 사이즈보다 16byte만큼 더 많은 공간을 차지하게 됩니다

그 이유는 동적 메모리가 할당 될 때 해당 메모리에 대한 정보들이 포함되어지기 때문입니다

할당된 메모리(chunk) 의 정보들은 pre_size, size, fd, bk, fd_nextsize, bk_nextsize가 있습니다

pre_size : 이전의 chunk가 free되면 설정되는 값입니다 ( 이전 chunk의 크기 - P플래그 )

  해당 정보를 이용해서 이전 chunk의 위치를 알아냅니다

size : 현재 chunk의 크기 정보

chunk는 8바이트의 단위로 정렬되는데 하위3bit는 플래그용도로 사용되며, 마지막 1bit는 P플래그입니다

P플래그란 PREV_INUSE이며 이전의 chunk가 사용되고있는지 free되었는지를 확인해주는 지표입니다

P플래그값이 1이면 사용중, 0이면 free되어 있다는 정보를 가집니다

fd : 이전 chunk의 주소값 / bk : 다음 chunk의주소값

fd와 bk는 unsorted chunk list에서 사용되어 지는 값들입니다

chunk가 동적 할당되고 free되어지면 사라지는것이 아니라 unsorted chunk list에 들어가게 됩니다

위의 소스코드에서 free되는 순서는 c - b - a 의 순서입니다

unsorted chunk list안에 a - b - c 의 순서로 위치해있겠죠? 따라서 a의 fd =  b , b의 fd = c 가됩니다



DFB는 free()함수의 실행을 바탕으로 unlink매크로를 이용한 공격법입니다 ( 원하는 주소에 원하는 값을 입력할 수 있다 )

unlink매크로가 무엇이냐면, 각 chunk들이 free되면 list안으로 들어간다고 했습니다. 해당 리스트안에서 fd와 bk에 의하여 각각의 

chunk들은 서로 연결되어 있는 상태입니다. 한 chunk에 대해서 fd와 bk를 제거함으로써 해당 chunk를 제거할 수 있다 : unlink


unlink매크로 발생 조건 : free된 chunk의 크기와 같은 chunk를 동적할당할 때 free된 이전 chunk를 재사용할 때 ( UAF )

         chunk를 free하려고 했을 때 이전의 chunk가 free되어진 상태이다 ( P플래그=0 ) => 합병발생


unlink매크로가 발생되면 다음과 같은 공식이 성립됩니다

fd + 12 = bk

bk + 8 = fd 


해당 공식을 이용해서 원하는 주소에 원하는 값을 입력시킬 수 있습니다


해당 내용의 실습은 http://itsaessak.tistory.com/136 링크에 있습니다