Pwnablekr_Toddlers Bottle_bof

링크에 접속하면 코드와 ELF 실행 파일을 얻을 수 있다. 문제에서 nc를 이용하여 접속하기를 요구하고 있다.

C언어 코드다. 핵심 알고리즘은 다음과 같다.

  • func에 인자로 0xdeadbeef를 넣고 호출
  • func에서, gets로 버퍼에 입력값을 받음
  • func에서, func의 인자가 0xcafebabe인지 확인

함수 인자로 0xdeadbeef를 넣는데, 문제의 조건은 인자가 0xcafebabe이기를 요구한다. 이는 어떻게든 스택에 있는 함수 인자 값을 변형해야 한다는 의미이다.

주목할 점은 gets 함수를 사용한다는 점이다. 이 함수는 버퍼의 크기에 대한 정보를 받지 않기 때문에 오버플로우를 일으킬 수 있다. 인자로 스택의 주소를 넣어주었기 때문에 스택 오버플로우를 일으켜 인자가 있는 부분의 값을 바꿔줄 수 있다.

하지만 코드만으로는 정확한 스택 구조를 알 수 없다. ELF 실행 파일에서 직접 디스어셈블리 코드를 보아야 한다. IDA를 이용해 실행 파일을 디스어셈블 했다. 그 중 func 코드만 떼어냈다.

먼저 push ebp 코드로 스택에 ebp를 백업한 값이 들어간다는 것을 알 수 있다. sub 48h를 보아 지역변수를 위한 스택을 0x48만큼 확보했다는 것을 알 수 있다. 그리고 gets를 호출하기 전 ebp-0x2c 주소를 인자로 준다는 것을 알 수 있다. 마지막으로, ebp+8과 0xcafebabe를 비교하는 코드를 통해 ebp+8의 위치에 인자가 있다는 것을 알 수 있다.

오른쪽은 스택을 그림으로 나타낸 것이다.

함수 인자를 바꾸고 싶으므로, 함수 인자 위치까지 가기 위한 더미값을 넣는다. 그리고 함수 인자가 있는 위치에 0xcafebabe 를 넣어준다. 이 때, 리틀엔디안에 주의한다.

계산해 보면 더미값은 52바이트를 입력하고, 그 후 0xbe 0xba 0xfe 0xca를 넣어주어야 한다.

파이썬과 netcat을 이용하여 입력값을 주었다. 셸이 실행되면 ls 명령어로 flag 파일을 찾고, cat 명령어를 이용하여 읽는다. nc는 cat 명령어의 네트워크 버전이다. cat 명령어는 인자로 준 파일의 내용을 간단히 읽거나 쓸 수 있는 명령어이다. stdin을 읽고, stdout으로 쓴다.

flag는 daddy, I just pwned a buFFer :) 이다.


tags: writeup, pwnable, elf file, linux, c lang, memory corruption, stack overflow, x86asm