level16으로 로그인한 후 hint 파일을 확인하면 마찬가지로 소스코드가 주어져 있다. 이번에는 shell을 얻게 해주는 shell 함수가 있어서 ret overwrite인가 했는데, 그게 아니라 bof를 통해 call 포인터의 값을 shell 함수의 주소로 변조하는 것이었다.
소스코드를 확인해보면 void형 포인터 변수 call에 printit 함수의 주소를 넣어주는데, 프로그램의 마지막에서 이 call에 들어 있는 주소의 함수를 실행해 준다. 참고로 이 printit 함수는 "Hello there!\n"를 출력시켜주는 기능을 한다.
마찬가지로 fgets 함수로 buf의 크기보다 큰 48byte 입력을 받는데, 여기서 buf의 크기는 20byte이므로 28byte의 overflow가 일어난다. 이를 이용해 call의 값을 shell의 주소로 변조한다면 call();를 통해 call에 저장된 shell 함수를 호출하면서 shell을 얻을 수 있을 것이다.
buf와 call 사이의 거리, shell 함수의 주소를 확인하기 위해 문제 파일을 tmp로 복사하고 gdb로 열었다.
i func(info function) 명령어를 통해 shell의 주소를 확인할 수 있다. shell의 주소는 0x080484d0이다.
fgets 함수를 호출하는 main+28에 bp를 걸고 실행한 뒤 스택을 확인해서 buf의 스택 주소를 얻을 수 있었다. 또한 ebp-16를 x/wx로 확인해서 call 포인터의 스택 주소를 얻을 수 있었다.
buf : 0xbfffdea0
call : 0xbfffdec8
따라서 buf, call 사이의 거리가 40byte임을 알 수 있다. 그렇다면 40byte의 더미 값을 채워준 뒤 shell 함수의 주소인 0x080484d0를 little endian으로 입력해준다면 쉘을 얻을 수 있을 것이다.(여러 번 디버거에서 실행해보거나 ldd 명령어를 사용하면 aslr이 걸려있지 않은 것을 알 수 있다.)
payload만 전송한다면 쉘 명령어를 입력하기 전에 프로그램이 종료되므로 ; cat을 붙여줬다. 성공적으로 exploit 한 것을 볼 수 있다.
'Wargame > FTZ' 카테고리의 다른 글
[FTZ] level 18 (0) | 2021.06.06 |
---|---|
[FTZ] level 17 (0) | 2021.06.06 |
[FTZ] level 15 (0) | 2021.06.06 |
[FTZ] level 14 (0) | 2021.06.04 |
[FTZ] level 13 (0) | 2021.06.04 |