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, NULL, NULL, NULL) >= 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 |