ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • CHAPTER 2.HalloweenDay MakingFilm
    0x.STORY_TELLER/MakingFilm 2018. 4. 11. 11:44

    CHAPTER 2.HalloweenDay MakingFilm



    문제 링크 : https://github.com/pwnwiz/STORY_TELLER/tree/master/STORY_0x01

    Fastbin과 관련된 여러 문제들을 풀어보기도 하였고, 이해도 잘 된 것 같아 마무리 차원에서 문제를 만들어보게 되었다. 처음에는 엄청 어렵게 만들어볼까 생각했었지만, 푸는 사람들을 고려하여 문제 난이도를 하향하였기에 익스에 쓸모가 없어진 메뉴가 생기기도 하였지만, 어쨌든 익스는 정상적으로 진행이 된다.

    패스트빈과 관련된 문제의 핵심은 fake_chunk를 할당할 수 있는가이다. fd의 값이 조작이 되는 상황속에서 특정한 장소에 fake_chunk를 할당하여 그 곳의 값들을 오버라이팅하는 것이 정석인데, 그 장소가 스택이 될 수도 있고, 훅이 될 수도 있고 그건 문제마다 상이하다.

    이 문제를 풀기 위해서는 how2heap의 fastbin_dup과 fastbin_dup_into_stack의 개념을 이해하고 있어야 하며, malloc hook과 unsorted bin에 대한 개념을 알고있어야 익스와 릭이 가능하다.

    이 문제를 설계하면서 좋았던 점은 애매한 개념들을 확실하게 잡을 수 있었다. 64비트 체제에서는 청크가 16바이트 단위로 할당되기 때문에 실질적으로 fakechunk에 사용할 수 있는 크기는 [16xA]~[16*A+0xf] 영역까지이다. 그래서 여러 익스플로잇 코드에서 할당하는 사이즈가 달라도 똑같은 결과가 나타나는 것인데, 이 개념이 확실히 잡혀있지 않았었는데, 문제 설계과정에서 fake_chunk를 할당하는 경우를 설계할 때 완전한 이해가 가능했다. 이 처럼 문제를 만드는 것이 많은 도움이 되는 것 같기는 하다.

    이번 스토리는 HalloweenDay이다. 문제의 상황에 대해 설명하자면, 집으로 누군가가 초인종을 누르고 "Trick or Treat" 이라고 외치면 옵션을 통해 방문자에게 캔디를 주거나, 거절을 할 수 있다. 그리고 특이한 경우에 해당 방문자가 유령이라고 생각할 경우 유령 메뉴를 선택하여 특수한 작업을 수행한다.

    각각의 함수에 대한 코드를 살펴보자면

    void accept(information **human, int *index) // malloc을 사용하여 할당을 받는 부분 크기는 fastbin으로 한정
    {
       int size;
       printf("You have accepted visitors.\n");
       printf("How many candies will you give??\n>>");
       scanf("%d", &size); // 사이즈를 받는데 의미없음.
       
       if(*index>=10){ // index check;
           printf("Nope!!\n");
           exit(1);
      }
       
       if(size>32) { human[*index]=malloc(96); }
       else { human[*index]=malloc(size); }
       human[*index]->quantity=size;
       printf("What is your name? New visitor??\n");
       read(0, human[*index]->name, 28);
       printf("Hi, %s\n", human[*index]->name);
       
      (*index)

    Accept메뉴의 경우 사용자로부터 사이즈를 입력받는데, malloc hook 오버라이팅으로 익스를 의도하기 위해서 사이즈가 32보다 큰 값이 입력되면 96바이트로 동일하게 할당하도록 하였다. fake_chunk의 사이즈로 함수들의 주소값인 7f를 가져다 쓸 수 있다.

    void deny(information **human, int *index) // malloc된 부분을 free 해주는 부분
    {
       int select;
       if(*index<=0)
      {
           printf("You Can not Deny\n");
      }
       else
      {
           printf("You want to reset the memory??\n");
           printf("Select the Member\n");
           scanf("%d", &select);

           if(select <=0 || select > *index)
          {
               printf("You Don't even have memory\n");
               return;
          }

           free(human[select-1]);
           printf("OK.\n");
      }
    }


    Deny메뉴의 경우, free를 진행해주는데, 인덱스 값이 다른 함수들과 달리 -1된 값을 가져다 쓰기 때문에 정확한 분석을 해야지 원하는 값을 free할 수 있다. 이 부분을 통해 double free버그가 트리거된다.

    void visitor(information **human, int *index) // list부분 malloc한 값들을 확인할 수 있음
    {
       int choice;
       if(*index<=0)
      {
           printf("No visitor\n");
      }
       else
      {
           printf("Enter the NO you want to see\n>");
           scanf("%d", &choice);
           if(choice>=*index)
          {
               printf("No visitor\n");
          }
           else
          {
               printf("%s\n", human[choice]->name);
          }
      }
       
    }


    visitor함수의 경우 동적할당된 공간안의 데이터를 확인할 수 있는데, 원래는 이 부분을 통해 어떤 값을 릭을 하도록 설계하였지만, 난이도를 조절하는 과정에서 사실상 익스와는 상관없는 메뉴가 되어버렸다..

    void check_ghost(information **ghost, int *ghost_index) // libc leak pumpkin (smallbin 할당 및 프리)
    {
       char name_ghost[20];
       char xas[8]="pumpkin";
       char xsa[10]="nightmare";
       char xsee[10]="darkness!";
       for(int i=0;i<20;i++)
      {
        name_ghost[i]=NULL;
      }
       int choice;

       printf("You really think it is ghost???\n");
       printf("What is the name??\n");

       read(0, name_ghost, 20);

       if(strncmp(xas, name_ghost, 7)==0)
      {
       printf("You got me!!! haha\n");
           ghost[*ghost_index]=malloc(200);
          (*ghost_index)++;
      }

       else if(strncmp(xsa, name_ghost, 9)==0)
      {
           printf("how many candies you want to give??\n>");
           scanf("%d", &choice);
           if(choice<0 || choice>*ghost_index)
          {
               printf("Nope!!!\n");
               exit(1);
          }

           free(ghost[choice]);
      }
       else if(strncmp(xsee, name_ghost, 9)==0)
      {
       printf("Here's the secret you want to know..\n");
       scanf("%d", &choice);
       if(choice<0 || choice>*ghost_index)
      {
           printf("But you are not ready..\n");
           exit(1);
      }
       else
      {
           printf("%s\n", ghost[choice]->name);
           producer();
      }  
      }
       
    }


    문제의 핵심부분으로 해당 문제의 릭을 할 수 있는 메뉴이다. 유령의 이름을 입력 받아 각각 smallbin의 할당, 해제 및 unsorted bin의 main_arena+88을 릭 할 수 있다.

    void bonus(information **human, int *index)
    {
       int select;
       char tempname[28];
       printf("Angel has visited your house, and you may change one thing now.\n>>");
       scanf("%d", &select);
       if(select<0 || select > *index)
      {
           printf("You Failed gg..\n");
      }
       else
      {
           printf("OK. Write!\n>>");
           read(0, tempname, 28);
           if(strlen(tempname)>28)
          {
               printf("gg..\n");
          }
           strncpy(human[select]->name, tempname, strlen(tempname));
           printf("OK!!\n");
      }
    }


    bonus함수는 fd의 값을 조작할 수 있도록 설계되었는데, 메인 함수에서 19950610이라는 값을 입력하면 들어올 수 있다. 이 메뉴를 통해 28바이트 만큼의 값을 조작할 수 있는데, fake_chunk에서 malloc_hook 까지를 덮을 수 있도록 하였다.

    문제의 본 의도는 fastbin을 2~3개 할당 한 다음에 smallbin을 2~3개 할당하고 해제함으로써 unsortedbin의 fd의 값에 적히는 main_arena+88을 릭 한 다음, 해당 주소로부터 malloc_hook을 찾아 그 앞에 위치한 특정 함수의 주소값의 7f를 기준으로 -8한 위치에 fake_chunk를 할당 한 다음에 bonus 옵션으로 값을 덮어씌워 malloc_hook에 system 또는 oneshot을 하여 풀 수 있게 설계하였다.

    아래의 깃허브에서 풀 코드를 확인할 수 있다.

    https://github.com/pwnwiz/STORY_TELLER/tree/master/STORY_0x01

    '0x.STORY_TELLER > MakingFilm' 카테고리의 다른 글

    CHAPTER 3.Viva_La_Vida MakingFilm  (0) 2018.09.03
    CHAPTER 1. Nymph's_fault MakingFilm  (0) 2018.02.28

    댓글

Designed by Tistory.