쉬는시간/pwnable.kr

[pwnable.kr]Toddler - bof 풀이

happy-nut 2017. 5. 25. 10:01

pwnable.kr의 Toddler 파트에 있는 문제 가운데 하나인 bof 라는 문제입니다.

할머니께서 내게 말씀해 주셨는데 버퍼오버플로우가 가장 일반적인 소프트웨어 취약점이라고 합니다. 그게 사실인가요? 라고 하네요.

부럽게도 할머니가 왕년에 짱짱해커였던 모양입니다.


download 링크를 통해 다운로드를 받게 되면 bof라는 실행파일과 bof.c라는 소스코드를 얻을 수 있습니다. 우선 소스코드부터 열어봅니다. 저는 에디터로 vscode를 자주 사용하기 때문에 vscode로 열어보았습니다.

저희는 이 프로그램이 실행되고 있는 환경에 있는 flag라는 파일을 여는 것이 목표입니다. 그러기 위해서는 system("/bin/sh")과 같은 함수를 활용해서 키 파일에 접근할 수 있는 쉘을 얻어야 합니다.

코드를 잘 들여다 보면, func함수에서 저희의 목표인 system("/bin/sh")이 보이는데, key에 0xdeadbeef라는 값을 줘 놓고는 key가 0xcafebabe가 아니면 그 함수를 실행시켜주지 않습니다.

하지만 overflowme라는 배열은 32바이트라는 크기제한이있는 반면 gets는 사용자가 엔터를 때리기 전까지 계속 받는 함수이기 때문에 입력값이 32바이트를 넘어가게 되는 경우 오버플로우 취약점이 발생합니다. 주석에 smash me! 라고 취약점이 발생하는 부분을 친절히 써놓았네요.

스택오버플로우를 시키기 위해서는 메모리 구조에 대해 자세히 알고 있어야 합니다. 하지만 이 문제를 푸는 사람들은 메모리 구조는 알고 있으리라 생각하기 때문에 자세히 설명하지는 않겠습니다.

아무튼 지금 같은 경우 func의 스택프레임을 기준 잡아 볼 때 overflowme라는 배열 아래에 saved된 ebp가 들어있고, return address, key 순으로 들어가 있을 것 같습니다.

그래도 혹시 모르니 IDA를 이용해 분석을 해봅니다.

IDA는 사실 변수 명들을 전부 guessing을 해서 디컴파일해주기 때문에, overflowme라던가 canary같은 건 전부 제가 보기 편하게 바꿔준 것입니다.  소스코드에는 없던 canary가 추가되었네요. canary는 overflow와 같은 스택변조를 감지하기 위해 만들어진 녀석인데, 만약 canary에 처음에 들어갔던 값과 리턴할 때 비교한 canary 값이 다르다면, "무언가 나도 모르는 사이 다른값이 씌여졌다..!" 라고 판단합니다. 하지만 지금 같은 경우에는 사실 의미가 별로 없습니다. canary는 func이 라인 13에서 리턴할 때까지 변조를 감지하는 데 아무런 도움을 못 줍니다. return이 되어서야 XOR결과로 판단을 하기 때문이죠. 하지만 system("/bin/sh");은 그 return하기 전에 있기 때문에 잘 익스플로잇을 한다면 어떠한 값으로 canary를 덮어 쓰든 system함수 프레임으로 넘어가게 됩니다.

IDA에서 스택을 열어봤습니다.

key는 ebp + 0x08 지점에, overflowme는 ebp - 0x2C 지점에 있네요. overflowme를 overflow시켜서 key까지 도달하려면 0x2c+0x08 인 52바이트 만큼 값을 넣어줘야 한다는 뜻이 되겠습니다.

파이썬은 이런 경우에 참 편리한데, payload를 다음과 같이 작성하면 될 것 같네요. pwnable.kr의 서버가 리틀엔디안이기 때문에 뒷 부분을 리틀엔디안 형식에 맞추어 넣어야 하는 것에 주의해야 합니다.

이제 이 페이로드를 pwnable.kr 의 bof에 삽입하면 쉘을 얻어낼 수 있습니다.

python 으로 입력한 payload가 nc 를 통해 pwnable.kr의 bof에 삽입되어 system이 실행되었고, cat으로 앞의 출력이 끝나면 stdout을 파이핑 하도록 했습니다. 만약 cat을 해주지 않으면 stdin이 close되기 때문에 쉘이 종료되서 flag파일을 열어볼 수 없게 됩니다.

아무튼, 문제는 잘 풀렸습니다.