본문으로 바로가기

해커스쿨 FTZ level18

category WargameFTZ 7년 전

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의 쉘을 얻을 수 있다.














WargameFTZ카테고리의 다른글

해커스쿨 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