이번에 풀이할 Basic_BOF #1은 많은 시행착오를 겪으며, 마침내 혼자 힘으로 풀어낸 첫 pwnable 문제다.
문제 화면에서 다운로드 버튼을 눌러 파일을 받으니, 위처럼 아무 확장자도 없어서 처음에는 좀 황당했었다. ELF 파일은 원래 그런가 싶어서 ubuntu를 켜서 확인해 봤다.
참고로 64bit 리눅스로 실행할 경우 처음에는 해당 파일을 찾지 못했다는 오류가 뜨는데, 아래 링크를 참고해 라이브러리들을 설치한다면 해결할 수 있다. 문제 파일이 32bit라 64bit 환경에서는 호환되지 않아 뜨는 오류다.
파일을 실행시키니 먼저 입력을 받고 [buf]와 [check]를 출력해준다. [buf]는 사용자의 입력을 출력해주는 것 같다.
자세한 동작을 알아보기 위해 ida로 문제 파일을 열어 봤다.
main 함수를 찾아서 F5를 눌러 c언어로 디컴파일 해봤다. 확실히 c언어를 선행적으로 배우니 코드 해석이 수월했다!
해석해본 동작은 다음과 같다.
int 형 변수 v5에 67305985 값을 넣어줌
-> fgets 함수로 45byte 만큼 사용자의 입력을 읽어서 char 형 변수 s(배열인 것 같다.)에 넣어줌
-> s에 들어 있는 문자열을 [buf] : 형식으로 출력(배열이 확실하다.)
-> [check] 형식으로 v5의 값을 16진수로 출력
-> v5의 값이 67305985나 -559038737이 아니라면 "You are on the right way!"를 출력
-> v5의 값이 3735928559라면 "Yeah dude! You win!\nOpening your shell..."을 출력하고 dash 쉘을 실행
즉 v5의 값을 3735928559로 만든다면 쉘을 얻을 수 있는 것이다.
gets, scanf 등의 취약한 입력 함수 대신 취약하지 않은 fgets 함수를 써서 입력을 받아 코드만 봤을 때는 쉘을 얻는 것이 불가능해 보였다.
취약 코드를 찾다 발견했는데, 이 부분은 스택에서 s, v5의 위치를 나타내는 것 같았다.
계산기를 통해 스택상의 s, v5의 거리가 40(10진수)임을 확인하고 깨달았다. 취약점은 바로 fgets 함수로 45byte만큼 입력을 받아 s에 값을 넣어주지만 정작 s의 크기는(v5의 거리는) 40이기 때문에 스택 오버플로우가 발생한다는 것이다.
잘 그리진 못했지만 위는 그림판으로 나타내본 s와 v5의 스택에서의 모습이다. 스택은 거꾸로 자라기 때문에 이 s 변수의 메모리 공간을 오버플로우 시키면 v5 값에 영향을 줄 수 있다.
h 단축키를 누르면 10진수 숫자를 16진수로 변환할 수 있다. v5의 값이 0xdeadbeef일 때 쉘을 얻을 수 있으므로 40바이트 만큼 임의의 값으로 채운 후 나머지 4바이트를 0xdeadbeef가 되게끔 만들어주면 될 것 같다.
우리 집에 gdb 있는데... 메모리 보고 갈래? 에서 배운 `python -c`를 사용해서 exploit을 하려했지만 명령어를 문자열로 받아 들여서 실패했다..
여러 방법을 시도해봐도 되지 않아 구글링을 해보니 pwntools라는 pwnable 문제 풀이를 도와주는 파이썬 모듈의 존재를 깨달았다.
from pwn import * # pwntools import
payload = b'A' * 40 + p32(0xdeadbeef) # payload 생성 "A"*40+"\xef"+"\xbe"+"\xa"
p = remote("ctf.j0n9hyun.xyz", 3000) # HackCTF 서버에 접속해 exploit
# p = process("./bof_basic") 로컬 파일 exploit 코드
p.sendline(payload) # payload를 입력 값으로 전송
p.interactive() # 사용자 입력 모드
위는 pwntools 모듈을 사용해서 짜본 python exploit 코드다.(왜 파이썬을 공부했는지 깨달았다!)
1행 : pwntools 임포트
3행 : payload 생성, 에러 없이 성공적인 exploit 문자열을 생성하기 위해 'A' 앞에 byte를 뜻하는 b를 붙여줬고, 32비트 리틀 엔디안 방식으로 0xdeadbeef를 만들어주기 위해 p32 함수를 사용.
5행 : remote 함수로 문제에 나와있는 서버로 접속
#6행 : 로컬 환경에서 exploit 코드
8행 : 만든 payload 문자열을 sendlin 명령어를 사용해 입력 값으로 전송
10행 : 쉘을 획득한 후 flag를 확인해야하므로 interative 함수를 사용해 사용자 입력 모드로 대기
작성한 python exploit을 실행해서 성공적으로 쉘을 획득한 후 interactive 모드에서 ftz에서 배웠던 cat 명령어를 사용해 flag를 얻었다.
이번 write-up은 처음 풀어본 문제, 첫 write-up 작성이라 풀이 뿐만 아니라 겪은 시행착오도 적느라 좀 길게 작성했는데(시간도 오래 걸렸다..), 다음 write-up부터는 핵심만 빠르게 정리해 보겠다.
'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] 내 버퍼가 흘러넘친다!!! (0) | 2021.03.18 |
[HackCTF] Basic_BOF #2 (0) | 2021.03.16 |