서론
안녕하세요, 이번에는 Return Address Overwrite라는 문제를 풀어보겠습니다. 언제동안 버퍼오버플로우만 하는건지. 이제야 다시 몇년 전의 제 진도를 따라잡는군요..
음.. 이 글을 다 쓴 줄 알아서, 면접 때 보여줄려다가 없길래 굉장히 쪽팔렸습니다..
쓸데없는 소리는 그만하고 풀이를 시작하겠습니다. 이 문제는 예제에서 풀었던 그대로 풀이하시면 됩니다.
풀이 (겉보기)
문제 파일을 다운로드하고 cat 명령어를 통해 소스코드를 읽습니다.
setvbuf라는 함수를 자주 까먹는데 이참에 기억해둬야겠습니다.
분석은 사실상 예제를 보면 됩니다만 여기서도 적어보겠습니다.
입력이 scanf("%s",buf);인 것을 보아 여기에서 오버플로우가 일어나기 쉽습니다. %s는 입력 문자열의 길이제한을 두지 않기 때문입니다.
이 문제에서는 입력을 길게 준다면 main함수의 반환 주소를 덮을 수 있습니다.
setvbuf 함수에 관해서는 드림핵에서는 설명이 없지만 좀 찾아봤습니다.
https://dojang.io/mod/page/view.php?id=763
https://modoocode.com/new-page/62
여기서
- _IOFBF 완전한 버퍼링(Full Buffering): 앞에서 설명한 fully buffered 스트림을 일컫는다.
- _IOLBF 행 버퍼링(Line Buffering): 출력시, 버퍼가 채워지거나 스트림에 개행 문자가 입력되었다면 데이터가 버퍼에서 출력된다. 입력 시에는 버퍼가 개행 문자를 만날 때 까지 버퍼를 채우게 된다.
- _IONBF 버퍼링 사용 안함(No Buffering): 버퍼를 사용하지 않는다. 각각의 입출력 작업은 버퍼를 지나지 않고 요청 즉시 진행되며 이 겨우 buffer 인자와 size 인자는 모두 무시된다.
2라는 인자는 _IONBF로 버퍼를 사용하지 않습니다. 바로 즉각적으로 입력받고 출력하고.. 아마 문제에서 입력 출력에서 생기는 오류를 방지하기 위한 부분으로 보입니다. 사실 exploit에서 그렇게 신경 쓸 부분은 아닌 것이죠.
그래서 우선 해당 소스코드는 buf에 입력받는 코드입니다. 여기서 우리는 main함수의 RET를 bufferoverflow로 수정해서 쉘을 실행시키는 것입니다.
GDB
gdb-pwndbg rao
get_shell의 주소는 0x00000000004006aa에 위치함을 알 수 있습니다.
b *main
r
을 하고
main + 35부터 살펴봅니다.
위 코드를 보면 buf는 rbp-0x30에 있고 스택 프레임 구조에서 rbp 주소에는 SFP가 들어있고 그 다음 주소에 RET가 들어있습니다.
leave :
mov esp, ebp
pop ebp
ret :
pop eip
jmp eip
을 생각하시면(32bit 기준 설명) 되겠습니다.
그래서 BOF를 실습하기 위해서 우리는 0x30 + 0x8을 대충 문자로 채운 다음 rbp+0x8인 RET를 get_shell함수의 주소로 변조하겠습니다.
Exploit
저번 글에서 어느정도 설명했는데, 제가 부여받은 url과 포트는 우와 같으므로
remote('host1.dreamhack.games',20444)로 했습니다.
remote('url',portnumber)의 형식이니까요
그리고 넣을 문자열 ex에 'A'로 0x30, 즉 buf를 채우고
'B'로 0x8 SFP를 채우겠습니다.
그 뒤에 리틀엔디언, get_shell의 주소를 넣어주겠습니다.
input : 이라는 문자열이 실행하면 나타나니 recv 해주시고, ex를 입력합니다.
이후 쉘 권한을 얻을테니 interactive합니다.
이렇게 익스플로잇 코드를 작성했습니다.
네 이렇게 문제를 풀었습니다. 감사합니다.