2017. 6. 16. 14:48ㆍSystemHacking/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 링크에 있습니다
'SystemHacking > System' 카테고리의 다른 글
가상머신에서 C언어 파일 컴파일 과정 (0) | 2017.10.12 |
---|---|
[7] PLT / GOT / objdump활용법 (0) | 2017.06.14 |
[6] Format String Bug [FSB] (0) | 2017.06.08 |
[5] Heap Buffer Overflow ( Heap기반의 버퍼오버플로우 ) (0) | 2017.06.07 |
[4] 환경변수를 이용한 버퍼 오버플로우 공격 ( 에그쉘) (1) | 2017.06.05 |