Notice
Recent Posts
Recent Comments
Link
«   2024/07   »
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
Tags
more
Archives
Today
Total
관리 메뉴

kaka09

문제풀이로 알아보는 TICTOU 취약점 본문

Pwnable

문제풀이로 알아보는 TICTOU 취약점

kaka09 2017. 8. 6. 19:55

[사진]1-1





Nebula exploit-exercises를 공부하다 TICTOU란 기법을 통해 문제를 풀어야 하는 상황이 나와 구글로 찾는중.. 취약점에 대한 원리와 상세한 설명보다는 어디 보안회사들의 가이드라인 및 과거 이정훈씨가 대회에서 상금을 탔다는 내용이 주를 이루어 좀 벙?쪄있었다.. 그래서 외국 문서들을 찾다 외국위키에서 설명이 잘 되어 있어서 해당 기법에 대해 이해를 하고 문제를 풀어낼 수 있었다..


우선 TICTOU(Time-of-check Time-of-use)기법은 일종의 Race Condition을 이용한 공격기법 이라고 볼 수 있다. 

다음의 예제를 살펴보자





 Victim

 Attacker 

   if (access("file", W_OK) != 0) {

   exit(1);
}

fd = open("file", O_WRONLY);
// Actually writing over /etc/passwd
write(fd, buffer, sizeof(buffer));

   //

// After the access check symlink("/etc/passwd", "file"); // Before the open, "file" points to the password database // //

[표]1-1


Victim에서의 코드를 살펴보면 acess함수에 의해 파일의 쓰기권한을 검사한다. 만약 쓰기권한이 존재하지 않으면 프로그램을 종료가 되고, 쓰기권한이 존재하면 해당 파일을 열어 쓰기작업을 진행한다. 취약점 포인트는 바로 access 함수에서 파일의 권한을 체크할때 일어난다고 보면 된다. 만약 해커가 심볼릭 링크로 쓰기권한이 있는 임시파일과 /etc/passwd 파일 2개에 대해 동일한 심볼릭 링크를 걸어 놓는 프로그램을 백그라운드로 실행시킨 다음 victim을 실핼한다고 가정한다. 만약 프로그램을 실행하고 access 함수 수행되는 시점에 쓰기 권한이 있는 임시파일에 걸리게 된다면 해당 조건문은 무사히 통과되어 /etc/passwd 파일이 쓰기모드로 열려 원하는 작업을 할수 있게 된다.



Nebula level10번 풀이를 통해 더 자세하게 알아 보도록 하자



(basic.c)download
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
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

int main(int argc, char **argv)
{
  char *file;
  char *host;

  if(argc < 3) {
      printf("%s file host\n\tsends file to host if you have access to it\n", argv[0]);
      exit(1);
  }

  file = argv[1];
  host = argv[2];

  if(access(argv[1], R_OK) == 0) {
      int fd;
      int ffd;
      int rc;
      struct sockaddr_in sin;
      char buffer[4096];

      printf("Connecting to %s:18211 .. ", host); fflush(stdout);

      fd = socket(AF_INET, SOCK_STREAM, 0);

      memset(&sin, 0, sizeof(struct sockaddr_in));
      sin.sin_family = AF_INET;
      sin.sin_addr.s_addr = inet_addr(host);
      sin.sin_port = htons(18211);

      if(connect(fd, (void *)&sin, sizeof(struct sockaddr_in)) == -1) {
          printf("Unable to connect to host %s\n", host);
          exit(EXIT_FAILURE);
      }

#define HITHERE ".oO Oo.\n"
      if(write(fd, HITHERE, strlen(HITHERE)) == -1) {
          printf("Unable to write banner to host %s\n", host);
          exit(EXIT_FAILURE);
      }
#undef HITHERE

      printf("Connected!\nSending file .. "); fflush(stdout);

      ffd = open(file, O_RDONLY);
      if(ffd == -1) {
          printf("Damn. Unable to open file\n");
          exit(EXIT_FAILURE);
      }

      rc = read(ffd, buffer, sizeof(buffer));
      if(rc == -1) {
          printf("Unable to read from file: %s\n", strerror(errno));
          exit(EXIT_FAILURE);
      }

      write(fd, buffer, rc);

      printf("wrote file!\n");

  } else {
      printf("You don't have access to %s\n", file);
  }
}



Nebula level10의 소스코드이다.  취약점 포인트는 24번째줄 access 수행시점에서 발생한다. 최종목적은 권한체크를 우회하여  60번째줄 read를 수행할 때 원하는 파일 내용을 읽어내야 한다.




[사진] 1-2


해당 문제에서는 권한이 없는 token 파일의 내용을 뽑아내야 한다.






[사진] 1-3



[사진]1-2와 같이 읽기 권한이 있는 /tmp/tmptoken 이라는 임시파일을 생성하고, ln -fs 옵션을 이용하여 임시토큰파일과 실제 토큰파일에 대해 심볼릭 링크를 거는 무한 스크립트문을 백그라운드로 돌린다. 여기서 -fs옵션은 링크를 건다음 삭제시키는 옵션이다. 만약 -fs옵션을 주지 않으면 링크파일이 존재한다는 에러가 출력되면서 링크를 반복적으로 걸 수 없다.



원격 서버에서 nc로 18211 포트를 열고 대기를 한다.



[사진] 1-4


18211 포트를 열고 대기하고 있으면 flag10이 실행될때 메세지를 해당 서버로 보내줄



[사진]1-5



생성된 심볼릭 링크 파일과 nc를 열어둔 원격 서버의 주소를 인자로서 flag10을 몇번 실행하다 보면 wrote file! 메세지와 함께 token값을 192.168.200.132 서버로 전송이 되는것을 확인할 수 있다. 192.168.200.132에 들어가서 token값이 전송되었는지 확인해보자




[사진]1-6


[사진]1-5의 결과를 살펴보면 test 메세지와 토큰값으로 추정되는 메세지가 보인다. test 메세지가 찍힌 이유는 flag10이 access와 read를 수행할때 임시토큰파일을 이용했기 때문이라고 할 수 있다. 즉 반복적으로 심볼릭 링크를 걸고 삭제하는 스크립트가 실행되기 때문에 실제 flag10을 실행하고있을때 어떤 파일들이 사용될지는 모른다. 임시토큰파일을 가리킬 수도 있고 실제 토큰파일을 가리킬 수도 있다. 




[사진]1-7



잘 이해가 안된다면 위 사진을 참고하자.. 지금까지 과정의 요약이라고 할 수 있다. 위에서 access로 파일 권한을 체크하고 밑에서 권한체크한 파일에 대해 열고 읽는 작업을 시도한다. 하지만 access를 수행할때와 read를 수행할때 어느정도 시간차가 존재한다. 만약 여기서 access가 수행될때 임시토큰파일을 가리키게 된다면 그 밑에 코드를 쭈욱~ 실행할 수 있다. 문제는 여기서 도중에 파일이 바꿔치기 당하는 셈이라 보면된다.(ln -fs /home/flag10/token /tmp/attack 으로 인해..) 그래서 read가 수행되는 시점에서 실제 원본토큰파일을 읽어낼 수 있었던 것이다. 물론 이 방법이 한큐에 성공되지 않는다. 일종의 시간차 공격이기 때문에 여러번 수행하여야 성공확률이 높아지는 공격이라 할 수 있다.