blackbearwow 2022. 4. 17. 17:14

이 문제는 답을 알려준 문제이다. 하지만 모르는 내용이 많이 나와 정리해보자.

// Name: uaf_overwrite.c
// Compile: gcc -o uaf_overwrite uaf_overwrite.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

struct Human {
  char name[16];
  int weight;
  long age;
}; //size: 0x20

struct Robot {
  char name[16];
  int weight;
  void (*fptr)();
};

struct Human *human;
struct Robot *robot;
char *custom[10];
int c_idx;

void print_name() { printf("Name: %s\n", robot->name); }

void menu() {
  printf("1. Human\n");
  printf("2. Robot\n");
  printf("3. Custom\n");
  printf("> ");
}

void human_func() {
  int sel;
  human = (struct Human *)malloc(sizeof(struct Human));

  strcpy(human->name, "Human");
  printf("Human Weight: ");
  scanf("%d", &human->weight);

  printf("Human Age: ");
  scanf("%ld", &human->age);

  free(human);
}

void robot_func() {
  int sel;
  robot = (struct Robot *)malloc(sizeof(struct Robot));

  strcpy(robot->name, "Robot");
  printf("Robot Weight: ");
  scanf("%d", &robot->weight);

  if (robot->fptr)
    robot->fptr();
  else
    robot->fptr = print_name;

  //robot->fptr(robot);

  free(robot);
}

int custom_func() {
  unsigned int size;
  unsigned int idx;
  if (c_idx > 9) {
    printf("Custom FULL!!\n");
    return 0;
  }

  printf("Size: ");
  scanf("%d", &size);

  if (size >= 0x100) {
    custom[c_idx] = malloc(size);
    printf("Data: ");
    read(0, custom[c_idx], size - 1);

    printf("Data: %s\n", custom[c_idx]);

    printf("Free idx: ");
    scanf("%d", &idx);

    if (idx < 10 && custom[idx]) {
      free(custom[idx]);
      custom[idx] = NULL;
    }
  }

  c_idx++;
}

int main() {
  int idx;
  char *ptr;
  
  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);

  while (1) {
    menu();
    scanf("%d", &idx);
    switch (idx) {
      case 1:
        human_func();
        break;
      case 2:
        robot_func();
        break;
      case 3:
        custom_func();
        break;
    }
  }
}

소스파일을 보면 Human구조체, Robot구조체, custom으로 0x100이상의 메모리를 malloc 동적 할당한다.

 

알아야 할것:

heap에서 bin은 free된 청크들을 관리하는 것이다.

tcachebin, unsortedbin

0x410이하의 청크는 tcachebin에 할당된다.

0x410초과의 청크를 할당하고, 해제하면 unsortedbin에서 관리된다.

unsortedbin에서 첫번째 청크는 fd, bk가 항상 main_arena+alpha로 고정된다.(같은 libc라면)

main_arena는 항상 libc_base에서 같은 거리에 있다.

tcachebin은 topchunk와 인접해도 병합 대상이 아니다.

unsortedbin은 topchunk와 인접하면 병합 대상이다.

linux는 heap 할당을 first fit을 채택중이다. 참고: https://code1018.tistory.com/192

 

시나리오:

custom으로 0x500크기의 청크를 2번 할당하고 0번째 청크를 free한다.

custom에서 0x500크기의 청크를 할당하고 데이터는 한바이트만 전송한다.

heap는 first fit방식이므로, free된 청크의 자리에 할당된다. 

main_arena+alpha값이 출력될거고, 해당값을 이용해 libc_base값을 구한다.

원가젯주소를 구하고 human->age에 넣는다.

robot_func()실행하면 원가젯 실행.