이번에 풀이할 문제는 HackCTF의 Offset 문제다. 개인적으로 이번 문제는 푸는 방법이 좀 참신하게 느껴졌다.
파일은 offset이라는 elf 파일이 주어져 있다. 실행을 해 동작을 먼저 확인한 후, 보호 기법, 코드를 확인하겠다.
문제 파일을 실행하면 "Which function would you like to call?"이라는 문구가 출력된 후 입력을 받는데, 1을 입력하니 프로그램이 그대로 종료됐다.
보호 기법은 canary 빼고는 모두 걸려 있는 것을 볼 수 있다.
ghidra로 main 코드를 확인해보면 위와 같다. gets 함수가 눈에 띄는데, 이 gets 함수를 통해 오버플로우를 일으킬 수도 있을 것 같다.
gets 다음에 호출되는 select_func 함수도 확인해봤다.
입력 값이 매개 변수로 전달되는데, 이 입력 값이 "one"이라면 one 함수를 실행해 주는 것을 볼 수 있다.
NX bit가 걸려 있어 쉘 코드를 삽입할 수가 없기 때문에 혹시 쉘이나 flag를 얻게 해 주는 함수가 있는지 살펴봤다.
print_flag라는 flag를 얻게해주는 함수가 존재하는 것을 알 수 있다. gets 함수를 이용해 오버플로우를 일으켜, ret를 print_flag의 주소로 변조하는 방법도 생각해봤지만 아무래도 PIE 보호 기법이 걸려 있어 base 주소를 얻지 않는 이상 ret 변조를 이용한 flag 획득은 힘들 것 같다.
gets를 이용한 취약점만 생각하느라 푸는데 조금 시간이 걸렸는데, 풀고 나니 gets 함수는 페이크라는 것을 깨달았다.
취약점은 위 함수에서 발생하는데, 보면 strncpy로 입력 값(매개변수)의 0x1f만큼 local_2e로 복사하는 것을 알 수 있다.
0x1f는 10진수로 31인데, local_2e는 30byte의 char 배열 변수이므로 1byte 오버플로우가 발생한다.(off by one 취약점)
gdb로 확인해보면 local_2e 변수 바로 옆에 함수 포인터 local_10이 존재하는 것을 알 수 있는데, 이 말은 즉슨 local_10을 1byte만큼 변조할 수 있다는 것이다.
입력 값이 "one"이 아닌 이상 local_10은 two 함수의 주소를 갖게 되는데, gdb에서 확인해본 위 사진처럼 two 함수와 flag를 얻게 해주는 print_flag 함수는 단 1byte의 offset이 차이가 나는 것을 볼 수 있다.
따라서 입력 값을 30byte의 더미 값 + \xd8를 준다면 print_flag 함수가 호출될 것이다.
(python2 -c "print'A'*30+'\xd8'") | nc ctf.j0n9hyun.xyz 3007
exploit 코드가 굉장히 간단하기 때문에 pwntools 없이 python 인터프리터 모드로 코드를 짰다.
더미 값 A 30byte + '\xd8'로 payload를 생성해 |(파이프)를 이용해 대회 서버로 전송했다.
'Wargame > HackCTF' 카테고리의 다른 글
[HackCTF] Yes or no (0) | 2021.05.25 |
---|---|
[HackCTF] BOF_PIE (0) | 2021.05.11 |
[HackCTF] Simple_Overflow_ver_2 (0) | 2021.05.11 |
[HackCTF] Basic_FSB (2) | 2021.05.05 |
[HackCTF] x64 Simple_size_BOF (0) | 2021.04.28 |