우분투에 도커 등 설치 완료 후 UAF 고고~ 

https://velog.io/@leejiwon317/Dreamhack-Exercise-Docker-1nnyeqrt

 

Dreamhack - Exercise: Docker

Install Docker Engine on Ubuntu🔼위 링크를 참고하여 설치하였습니다.이렇게 뜨면 도커 설치 성공!이번 문제는 Dockerfile로 이미지를 빌드하고 컨테이너를 실행해 보기 위한 실습 문제!!!문제 파일을 다

velog.io

https://she11.tistory.com/153

 

[Dreamhack] uaf_overwrite - write up

Index문제보호기법 확인uaf_overwrite.c코드 분석전역 변수 선언human_func()robot_func()custom_func()문제 풀이Libc LeakLocal Exploit Issue 익스플로잇 uaf_overwriteDescription Exploit Tech: Use After Free에서 실습하는 문제입

she11.tistory.com

 

// 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;
};

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;
    }
  }
}

 

전역 변수 

struct Human {
  char name[16];
  int weight;
  long age;
};

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

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

두 구조체의 자료형을 보면 동일한 메모리 크기를 사용하는 것을 알 수 있다.

UAF(Use After Free 문제인 만큼 Human→age에 주소 값을 입력하고 해제하고 Robot 구조체로 재 할당하면, 재 할당 받은 Robot→fptr로 원하는 코드 흐름을 실행시킬 수 있을 것 같다. 또한, 주소를 담고 있는 custom 배열과 이를 참조하는 c_idx가 선언된다.

human_func()

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);
}

robot_func()

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);
}

Robot(2번) 메뉴를 선택하면 robot_function함수가 실행된다. Robot 구조체 1개를 동적할당 하고, weight를 입력받아 데이터를 저장한다. fptr에 대한 입력은 없지만, robot→fptr의 값이 NULL이 아니라면 fptr의 주소로 점프한다.

위의 두개의 함수를 통해 Human→age에 원하는 주소를 입력해두고, robot_func()을 실행하면 robot→fptr에 앞서 저장해준 Human→age값으로 robot→fptr()이 실행된다. 그렇다면 Human→age에 원샷 가젯의 주소를 넣으면 셸을 얻을 수 있을 것이다. 하지만 우리는 libc를 모르기 때문에, 메모리 릭을 통해 libc를 먼저 구해야 한다.

custom_func()

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++;
}

마지막으로 Custom(3번) 메뉴를 선택하면 custom_func함수가 실행된다. 먼저 첫 if문의 c_idx는 앞서 선언했던 전역변수이다. 이 함수가 실행될 때마다 마지막에 c_idx++를 해주므로, 총 10번을 실행할 수 있다.

입력받은 size가 0x100보다 크다면 custom[c_idx]에 size만큼의 동적할당을 해주고, 데이터를 입력받는다.

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

데이터를 입력받은 후, custom[c_idx]에 값을 출력해준다. 이 Data 부분에는 Unsorted bin을 free 했을 때 남아있던 fd 값이 출력된다. unsorted bin에 들어간 청크의 fd와 bk은 main 의 주소이고, 이 오프셋을 통해서 libc를 구할 수 있다.


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

idx가 unsigned int자료형으로 선언되었다. 만약 idx에 -1(음수)를 입력하게 되면 0xffffffff와 같은 형식으로 메모리에 입력된다. 그러면 할당된 메모리를 free하지 않는다.





 

 

 

 

 

'시스템' 카테고리의 다른 글

onone_gadget 설치 및 사용법 (펌)  (0) 2025.02.02
peda, pwndbg, gef 같이 쓰기 (펌)  (0) 2025.02.02
pwnable.kr UAF (리마인드)  (0) 2025.01.31
protostar net3  (0) 2025.01.31
protostar net1  (0) 2025.01.31
블로그 이미지

wtdsoul

,