ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Toddler's Bottle] bof write-up
    System hacking training/pwnable.kr 2018. 7. 1. 22:57

    toddler's bottle 의 세번째 문제 bof를 풀이하겠습니다. (사실 순서대로 풀이하려고 했는데 MD5 해쉬 충돌...? collision문제를 아직 풀지 못해서 먼저 작성하겠습니다.)

    5pt로 간단한 문제입니다.

    buffer overflow 는 가장 일반적인 소프트웨어 취약점 중 하나라고 알려주면서 bof 바이너리와 소스코드를 줍니다.

    먼저 소스코드를 확인해보면 아래와 같습니다.

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    void func(int key){
    	char overflowme[32];
    	printf("overflow me : ");
    	gets(overflowme);	// smash me!
    	if(key == 0xcafebabe){
    		system("/bin/sh");
    	}
    	else{
    		printf("Nah..\n");
    	}
    }
    int main(int argc, char* argv[]){
    	func(0xdeadbeef);
    	return 0;
    }

    간단합니다. bof 가 터지는 원인 중 하나인 gets 함수를 사용합니다. 의식의 흐름대로 코드 분석을 해보면

    main()에서는 0xdeadbeef 를 넘겨줍니다.

    func에는 overflowme라는 32byte의 배열이 존재하고 gets()로 overflowme에 입력을 받습니다.

    그리고 인자로 받았던 key값을 0xcafebabe 를 비교하며 맞다면 쉘을 실행 시켜주고, 아니라면 Nah.. 를 출력하며 함수의 역할이 끝납니다.

    이러한 흐름의 바이너리에서 원하는 쉘을 따기 위해서는 key의 값을 0xdeadbeef 에서 0xcafebabe로 바꿔줘야합니다. 여기서 대충 스택을 그려본다면

    이와 같을것으로 예상됩니다.

    그렇다면 overflowme는 func() stack frame중 어느 위치에 존재할 것이고, gets로 입력을 받기 때문에 bof를 터트려 0xdeadbeef 의 값을 0xcafebabe로 변경할 수 있을것입니다.

    [참고] gets()가 bof를 일으키는 이유는 입력값의 길이에 대한 제한이 없기 때문입니다.

    이제 정확한 overflowme의 위치가 어딘지 알아보기 위해 gdb로 열어보았습니다.

    gdb로 func 함수를 디스어셈해본 결과 버퍼의 크기는 0x48(72)byte이고 overflowme라는 배열은 cmp 전에 사용되기 때문에 ebp - 0x2c(48) 에 위치한다는 것을 알 수 있습니다.

    소스코드가 주어져있기 때문에 func+25 or func+36을 call 하는 부분이 어느 함수인지 알 수 있습니다. cmp는 소스코드에서 값을 비교하는 부분이 하나밖에 없기 때문에 쉽게 overflowme가 어느 위치에 존재하는지 알 수 있습니다.

    또 ebp+8의 위치의 값과 oxcafebabe를 cmp로 비교하는 부분에서 ebp+8의 위치에 0xdeadbeef 값이 있다는 것 또한 알 수 있습니다.

    그렇다면 이제 익스코드를 작성하면 됩니다.

    52byte의 dummy값(overflowme[32]+dummy(12)+SFP(4)+ret(4))으로 0xdeadbeef가 있는 위치로 간 뒤 0xcafebabe를 리틀엔디언으로 넣어주면 쉘이 뜹니다.

    이제 서버에 보내보겠습니다.

    flag값을 출력해냈습니다.

    이상 풀이를 마칩니다.


    번외로 checksec으로 canary found를 확인했었는데 여기서도 dummy값이 껴있다는 것을 알 수 있었습니다.

    반응형
Designed by Tistory.