이번에 풀이할 문제는 HackCTF의 g++ pwn 문제다. 문제 이름이 g++걸 봐서 c++ 소스 코드를 컴파일해주는 g++ 컴파일러가 생각난다.
문제 파일을 실행해보니 입력을 받고, 입력을 받은 값을 출력해주는 동작을 한다. 혹시하고 입력 값으로 많은 1 값을 줬지만 Segment fault 오류는 터지지 않는 것을 알 수 있다. bof 문제가 아닐 수도 있는 것 같다.
보호기법은 nx만 걸려있는 것을 알 수 있다.
ida는 제대로 해석을 못하는 것 같아서 ghidra로 main 함수를 확인해봤다. main 함수는 vuln 함수만 호출한다.
vuln 함수를 확인해보면 fgets 함수를 이용해 local_40에 32byte만큼 입력을 받는 것을 알 수 있다. local_40의 크기는 32byte인데, 32byte의 입력 값을 넣는다면 끝에 \x00이 삽입되어 1byte overflow는 가능하겠으나 다른 변수들이 많은 것을 봐서 sfp에는 접근이 불가능할 것 같다.
fsb도 생각해봤지만 출력 문에서는 서식 지정자를 제대로 사용해서 출력한다.
그러던 중 replace 함수에서 취약점을 발견했는데, replace 자체가 취약한 것이 아니라 입력 값 중 I인 값을 you로 치환해서 저장해주기 때문이다.
그렇다면 입력 값으로 I * 32를 준다면 'you'가 32번 저장될 것이기 때문에 overflow가 될 것이다.
테스트 해보니 정말로 I를 you로 치환해주는 것을 알 수 있다.
함수 중에는 get_flag라는 flag를 얻게 해주는 함수가 있는데, 적절히 I 값을 넣어줘 sfp까지 더미 값으로 채운 후 ret를 get_flag 함수의 주소로 변조하면 될 것이다.
gdb를 통해 buffer와 ret의 스택 주소를 구했다.
ret : 0xffffce3c
buf : 0xffffcde0
따라서 거리는 64byte인 것을 알 수 있다.
그렇다면 I를 21개 준다면 63byte가 채워지니 1byte의 dummy 값을 추가한 뒤 get_flag의 주소인 0x08048f0d로 ret를 변조하면 될 것이다.
from pwn import *
r = remote('ctf.j0n9hyun.xyz', 3011)
get_flag = 0x08048f0d
payload = b'I' * 21 + b'A' + p64(get_flag)
r.sendline(payload)
r.interactive()
'Wargame > HackCTF' 카테고리의 다른 글
[HackCTF] RTL_Core (0) | 2021.07.20 |
---|---|
[HackCTF] Random Key (0) | 2021.07.20 |
[HackCTF] RTL_World (0) | 2021.06.30 |
[HackCTF] Yes or no (0) | 2021.05.25 |
[HackCTF] BOF_PIE (0) | 2021.05.11 |