Pwnable/FTZ

FTZ - level9 [Buffer Overflow]

Lucvs 2020. 8. 28. 12:48

LEVEL 9

 

[level9] passcode : break

(NO DRAG, NO PASSCODE)


hint를 살펴보니 버퍼 오버플로우에 관한 문제인 것 같다. 바로 코드를 살펴보자.

 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
main(){
 
  char buf2[10]; //10바이트 크기의 buf2 선언
  char buf[10];  //10바이트 크기의 buf 선언
 
  printf("It can be overflow : ");
  fgets(buf,40,stdin);  //buf라는 변수에 40개(NULL포함) 입력받음
 
  if ( strncmp(buf2, "go", 2) == 0 ) //buf2의 처음 2개의 문자가 "go"와 일치한다면
   {
        printf("Good Skill!\n");
        setreuid( 3010, 3010 );  //level10의 권한 부여
        system("/bin/bash");  //쉘을 실행시킴
   }
}

 

<해결방법>

  1. 버퍼오버플로우를 발생시키기 위하여 노가다로 buf와 buf2 사이의 dummy 값을 예측하여 풀 수도 있다.
  2. gdb를 사용하여 정확하게 dummy의 크기를 파악하여 풀 수도 있다.

더 유용한 방법인 2번을 이용하여 풀어보자.

우선 /usr/bin/bof 프로그램을 level9 권한에서는 x(실행)권한밖에 주어져 있지 않기 때문에 hint의 코드를 이용하여 level9에서도 /usr/bin/bash 프로그램에 대한 gdb를 사용할 수 있도록 해보자.

/home/level/tmp 디렉토리로 이동하여 새로운 실행파일을 만들어주자.

이제 level9의 권한에서도 /usr/bin/bof 프로그램과 똑같은 기능을 하는 프로그램을 만들었다. 이제 이를 이용하여 gdb를 사용해 보자.

우선 level9을 gdb로 실행한다.


Intel 문법

<main+3> 부분에서 0x28(40바이트) 만큼을 빼주는데 통상적으로 초기에 선언된 변수들이다.

buf와 buf2가 각각 10바이트로 선언되어 있으므로 40바이트는 1차적으로 다음과 같이 구성된다.

 

| ret [4] | → 높은 주소

| sfp [4] |

| buf2[10] |

| buf[10] | → 낮은 주소

 

fgets 함수 위의 lea 명령어를 통해 buf의 주소가 전달된다. 또한 strncmp 함수 위에서도 buf2의 주소가 전달된다. 둘의 차이가 40 - 24 = 16 이므로 buf와 buf2의 주솟값 차이가 16바이트이다.

 

따라서 최종적으로 40바이트는 다음과 같이 구성된다.

 

| ret [4] | → 높은 주소

| sfp [4] |

| dummy [6] |

| buf2[10] |

| dummy [6] |

| buf[10] | → 낮은 주소

 

  • 스택에서 변수는 먼저 선언된 순서대로 높은 주소부터 들어가지만 이 변수에 값을 넣을 때는 낮은 주소부터 들어가게 된다.

따라서 16바이트의 무의미한 데이터와 그 뒤에 "go"라는 문자열을 넘겨주면 level10의 쉘이 따질 것이다.


att 문법

마찬가지로 buf의 주소(0xffffffd8)가 fgets 함수에 전달되고, buf2의 주소(0xffffffe8)가 strncmp 함수에 전달된다. 이것으로 미루어 보아 둘의 주소 차이가 0x10, 즉 16바이트 차이가 나므로 16개의 무의미한 데이터와 "go"라는 문자열을 프로그램에 전달에 주어야 한다.

 


이제 어떤 값을 넣어야 하는지 알았으므로 본래 목적 프로그램인 /usr/bin/bof 프로그램을 실행시키고 값을 넣자.

성공적으로 쉘을 땄다. my-pass 명령어를 통해 level10의 비밀번호를 얻자.


[level10] : interesting to hack!