본문으로 바로가기

해커스쿨 FTZ level18

category Wargame/FTZ 2018. 8. 5. 09:49

level18 --- why did you do it



우선 level18의 디렉터리를 확인한다.





attackme라는 의심스러운 파일이 존재한다. attackme는 level19의 권한을 가지고 있고, setuid가 걸려있는 파일이다.



우리가 공격할 대상이 attackme일 가능성이 크다고 생각하고 hint를 보자.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#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)
    {
      // count 변수가 100 이상이면 경고 메세지 출력한다.
      if(count >= 100)
        printf("what are you trying to do?\n");
      // check 변수가 0xdeadbeef이면, level19의 쉘 실행한다.
      if(check == 0xdeadbeef)
        shellout();
      else
        {
          // fds 비트를 0으로 초기화한다.
          FD_ZERO(&fds);
          // 키보드 입력으로 설정한다.
          FD_SET(STDIN_FILENO,&fds);
 
          if(select(FD_SETSIZE, &fds, NULLNULLNULL>= 1)
            {
              if(FD_ISSET(fileno(stdin),&fds))
                {
                  read(fileno(stdin),&x,1);
                  switch(x)
                    {
                      case '\r':
                      case '\n':        // 엔터가 입력되면 \a 출력한다.
                        printf("\a");
                        break;
                      case 0x08:        // 0x08이 입력되면 count의 값을 1만큼 줄인다.
                        count--;
                        printf("\b \b");
                        break;
                      default:                    // 나머지 문자가 입력되면
                        string[count] = x;         // string[] 배열에 한 글자씩 저장한다.
                        count++;                // count 변수의 값을 1만큼 증가시킨다.
                        break;
                    }
                }
            }
        }
    }
}
 
void shellout(void)
{
  setreuid(3099,3099);
  execl("/bin/sh","sh",NULL);
cs



hint의 소스가 생각보다 길어서 이해하기 힘들수 있다.

하지만 아래의 예제 소스와 같이 생각하면 좀 더 편히 이해할 수 있다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
 
int main()
{
        int a=10;
        int b=5;
        int c=4;
        int *pt=&c;
        int d=6;
        int e=25;
 
        printf("a=%d, b=%d, c=%d, d=%d, e=%d\n"*(pt+2), *(pt+1), *(pt+0), *(pt-2), *(pt-3));
}
 
cs



위와 같이 소스를 작성하면 결과는 어떻게 될까???




포인터에 +,- 연산을 통해 다른 주소에 접근 할 수 있다. pt는 int형 포인터 변수이기 때문에 +1을 하면 +4byte 씩 증가한다.


메모리 구조를 그려보면 아래와 같이 그려볼 수 있다.




위에서 보듯이 포인터, 혹은 배열을 이용해서 다른 주소에 접근 할 수 있음을 확인했다.

지금 이렇게 포인터와 배열의 접근을 중요시 하는것은 hint의 메모리 구조를 보면 이해할 수 있을 것이다.


hint의 메모리 구조는 아래와 같다.




지금까지의 level에서는 string[] 배열에서 overflow를 이용해 check의 값을 바꾸는 과정으로 공격했다.

하지만 string[] 배열이 먼저 선언되고 check가 나중에 선언되는 바람에 overflow를 통해서 접근할 수 없다.

따라서 주소 +,- 접근을 통해 공격해야하는 것이다.


우리는 hint의 소스를 가지고 배열의 인자를 음의 방향으로 접근하면 된다.


얼마나 인자를 음의 방향으로 이동해야 check 변수에 접근할 수 있는지 알기 위해 예제 코드를 보자.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
 
int main()
{
        char string[100];
        int check=10;
        int x = 5;
        int count = 0;
        fd_set fds;
 
        printf(" count =%d\n x     =%d\n check=%d\n"string[-12], string[-8], string[-4]);
}
 
cs



컴파일 후 실행하면 아래와 같은 결과를 얻을 수 있다.




string[] 배열에서 -4만큼 접근하면 check 변수에 접근할 수 있다.


이를 바탕으로 attackme를 공격해보자.


배열의 count 감소를 위해 \x08\x08\x08\x08 + \xdeadbeef 를 하면 level19의 쉘을 얻을 수 있다.














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

해커스쿨 FTZ level20 (format stirng)  (0) 2018.08.05
해커스쿨 FTZ level19 (Return To Libc)  (0) 2018.08.05
해커스쿨 FTZ level17  (0) 2018.08.04
해커스쿨 FTZ level16  (0) 2018.08.04
해커스쿨 FTZ level15  (0) 2018.08.04