profile image

L o a d i n g . . .

1. 문제

파일들을 확인한 모습이다.

 

Hint 를 확인하니 다음과 같은 소스코드가 들어있었다.

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
void shellout(void);
int main()
{
  char string[100];
  int check;
  int x = 0;
  int count = 0;
  fd_set fds;
  printf("Enter your command: ");
  fflush(stdout);
  while(1)
    {
      if(count >= 100)
        printf("what are you trying to do?\n");
      if(check == 0xdeadbeef)
        shellout();
      else
        {
          FD_ZERO(&fds);
          FD_SET(STDIN_FILENO,&fds);

          if(select(FD_SETSIZE, &fds, NULL, NULL, NULL) >= 1)
            {
              if(FD_ISSET(fileno(stdin),&fds))
                {
                  read(fileno(stdin),&x,1);
                  switch(x)
                    {
                      case '\r':
                      case '\n':
                        printf("\a");
                        break;
                      case 0x08:
                        count--;
                        printf("\b \b");
                        break;
                      default:
                        string[count] = x;
                        count++;
                        break;
                    }
                }
            }
        }
    }
}

void shellout(void)
{
  setreuid(3099,3099);
  execl("/bin/sh","sh",NULL);
}

살짝 길지만,, 분석을 해보면 다음과 같다.

 

if(count >= 100)
	printf("what are you trying to do?\n");
if(check == 0xdeadbeef)
	shellout();

1. count 가 100 이상일 경우 위의 멘트를 출력한다. (bof 를 예방하는 부분이다)

2. check 값이 0xdeadbeef 일 경우, 쉘을 실행시키는 shellout() 함수를 실행한다.

-> check 값을 0xdeadbeef 로 변경해 shellout() 을 실행시키는 것이 우리의 목표임.

 

 

read(fileno(stdin),&x,1);
                  switch(x)
                    {
                      case '\r':
                      case '\n':
                        printf("\a");
                        break;
                      case 0x08:
                        count--;
                        printf("\b \b");
                        break;
                      default:
                        string[count] = x;
                        count++;
                        break;
                    }

그리고 입력을 받는 부분이 중요한데, read 함수를 통해 1바이트만큼 입력을 받아 x에 저장한다.

그리고 switch 문을 통해 입력받은 x의 값에 따라 분기가 된다.

x 가 0x08 의 경우 count 가 1만큼 감소한다.

x 가 '\r' '\n' '0x08' 모두 아닐 경우엔 배열 string에 저장하고, count 를 1 증가시킨다.

 

 

2. 문제 해결 과정

 

그렇다면 우선 입력을 받아 값을 저장하는 string 버퍼와, 우리가 변경해야 할 값인 check 간 offset을 알아보자. 

0xdeadbeef 와 check 값이 같은지 비교하는 부분

check : ebp - 104

 

밑에 inc 이 있고, 다시 main의 초반부로 돌아가 while 문을 실행하는 걸로 보아 default:: 부분인 것 같다.

string : ebp - 100

 

 

즉, check 와 string 간 offset은 4로 check가 더 낮은 주소에 있다.

지금까지는 bof 를 통해 버퍼보다 높은 주소에 있는 값을 변경했다면, 이번엔 버퍼 보다 더 낮은 주소에 있는 값을 변경해야 하는 것이다. 어떻게 할 수 있을까?

 

입력을 받는 부분이 중요한데, 0x08 일 경우 count--; 가 실행된다.

따라서 count 값을 음수로 변경한 뒤, string[count] 에 0xdeadbeef 값을 한 바이트씩 넣어주면 된다.

 

 

따라서 payload는 다음과 같을 것이다.

"0x08"*4 + 0xdeadbeef

0x08 을 네 번 보내는 이유는, string 버퍼의 경우 char 형이기 때문이다.

string[-4] = xde

string[-3] = xad

string[-2] = xbe

string[-1] = xef

 

 

3. Exploit

위의 논리대로 payload 를 작성해보았다.

 

Level 19 password : swimming in pink

 

'Wargame > Hackerschool FTZ' 카테고리의 다른 글

[FTZ] 해커스쿨 FTZ level 19  (0) 2021.04.13
[FTZ] 해커스쿨 FTZ level 17  (0) 2021.04.13
[FTZ] 해커스쿨 FTZ level 16  (0) 2021.04.13
[FTZ] 해커스쿨 FTZ level 15  (0) 2021.04.12
[FTZ] 해커스쿨 FTZ level 14  (0) 2021.04.12
복사했습니다!