반응형
Use After Free 취약점
UAF 취약점
말 그대로 사용한 후 해제했을 때 취약점이 발생하는 것을 뜻합니다. 더 정확히는
heap 영역에서 할당된 ( malloc … ) 공간을 free하고 reuse 할 때 일어날 수 있는 취약점입니다.
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 | #include <stdio.h> #include <stdlib.h> int main(void) { int *heap1; int *heap2; int *heap3; heap1 = (int *)malloc(sizeof(int) * 50); heap2 = (int *)malloc(sizeof(int) * 50); printf("heap1 address : %p\n", heap1); printf("heap2 address : %p\n", heap2); *heap2 = 1234; printf("heap2 number : %d\n", *heap2); printf("free heap2 :)\n"); free(heap2); heap3 = (int *)malloc(sizeof(int) * 50); printf("heap3 address : %p\n", heap3); printf("heap3 value : %d\n", *heap3); return 0; } | cs |
sizeof(int) * 50 ( 200bytes ) 만큼 할당을 2번하고
두 번째 heap2에 값을 넣은 후 free해주었습니다.
그 후에는 heap3 를 같은 크기로 할당해주었으며
주소와 값을 print 해주었습니다. 그 결과 heap2의 address와 value가 같은 것을
확인할 수 있습니다.
이는 heap 메모리를 좀 더 효율적으로 사용하기 위해 반환된 heap영역의 크기를 기억해놨다가
같은 크기의 할당 요청이 들어오면 이전 영역을 재사용하게 합니다.
이는 malloc 함수에는 caching 기능이 있는데, Deferred Coalescing(병합 지연) 속성이라고 합니다. heap2를 free한 후 heap3을 다시 할당하면 병합하거나 분할하는 시간을 절약하고자 그 영역을 그대로 사용하게 해주는 겁니다.
결과적으로 메모리를 효율적으로 사용하지만 반대로 공간을 재사용할 경우, 원하지 않는 값을 참조할 수 있게 됩니다.
(2016년에 어떤 개발자가 \0 을 넣어주면서 한게 기억이 나네요)
<이 예제는 Use After Free 와 Heap Overflow를 다룹니다>
그 예제 소스는 아래와 같습니다.
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 37 38 39 40 41 42 43 44 45 | #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct{ char namep[10]; void (*print)(void*); }test; typedef struct{ char name[128]; }string; void printName(test *t) { printf("%s\n", t->name); } void shell(void) { printf("This is Shell\n"); } int main(void) { test *t1; string *s1; t1 = malloc(256); strcpy(t1->name, "DOG"); t1->print = (void*)printName; t1->print(t1); free(t1); s1 = malloc(256); scanf("%128s", s1->name); t1->print(t1); return 0; } | cs |
test, String 구조체 변수들을 선언해주었습니다.
이 때의 Heap 영역은 아래와 같이 할당됩니다.
여기서 주의깊게 봐야 되는건 같은 위치에서 각 이벤트들이 발생하고 있다는 겁니다.
test 할당 -> test 해제 -> string 할당 -> test 사용
을 하게 된다면 마지막 test사용에서 어떤 값으로 바뀌었을지 모르는 포인터를 참조하게 됩니다.
test 구조체가 free된 후 같은 위치에 string 구조체가 할당되는데 이 때,
test구조체의 멤버 변수 중 print라는 함수 포인터의 값을 덮을 수 있습니다.
원래는 t1->print = (void*)printName; 이 값이 들어가 있지만, 이 값을
shell 함수의 주소로 덮은 뒤 마지막 t1->print(t1); 이 코드가 실행된다면 PrintName함수가 아닌 Shell 의 함수가 실행될 것입니다.
main 에서 scanf 실행을 시킨 후 브레이크를 잡아보았습니다.
s1->name 에 알아보기 쉽게 aaaa값을 넣었습니다.
할당된 영역을 확인해보겠습니다.
입력된 값 아래보면 40062d주소가 보이네요
40062d의 주소에는
당연히 실행될 printName코드가 들어가 있습니다.
그러면 a를 16개 채우고 shell의 주소를 덮어준다면 어떻게 될까요.
이 예제는 Use After Free와 Heap Overflow를 알아보는 실습코드였습니다.
(_ _ )
반응형
'[ ★ ]Study > PWNABLE' 카테고리의 다른 글
[Tip] pwntool 함수 offset/plt/got 주소 찾기(pwntools) (0) | 2018.11.06 |
---|---|
Double Free Bug(DFB) (0) | 2017.09.18 |
system call table 정리 (0) | 2017.09.16 |
shellcode 만들기 2부 (0) | 2017.09.16 |
shellcode 만들기 1부 (2) | 2017.09.16 |
댓글