System hacking training/Hackerschool LOB
LEVEL 17 succubus write-up
fkillrra
2018. 5. 17. 20:42
zombie_assassin -> succubus
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 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | [zombie_assassin@localhost zombie_assassin]$ cat succubus.c /* The Lord of the BOF : The Fellowship of the BOF - succubus - calling functions continuously */ #include <stdio.h> #include <stdlib.h> #include <dumpcode.h> // the inspector int check = 0; void MO(char *cmd) { if(check != 4) exit(0); printf("welcome to the MO!\n"); // olleh! system(cmd); } void YUT(void) { if(check != 3) exit(0); printf("welcome to the YUT!\n"); check = 4; } void GUL(void) { if(check != 2) exit(0); printf("welcome to the GUL!\n"); check = 3; } void GYE(void) { if(check != 1) exit(0); printf("welcome to the GYE!\n"); check = 2; } void DO(void) { printf("welcome to the DO!\n"); check = 1; } main(int argc, char *argv[]) { char buffer[40]; char *addr; if(argc < 2){ printf("argv error\n"); exit(0); } // you cannot use library if(strchr(argv[1], '\x40')){ printf("You cannot use library\n"); exit(0); } // check address addr = (char *)&DO; if(memcmp(argv[1]+44, &addr, 4) != 0){ printf("You must fall in love with DO\n"); exit(0); } // overflow! strcpy(buffer, argv[1]); printf("%s\n", buffer); // stack destroyer // 100 : extra space for copied argv[1] memset(buffer, 0, 44); memset(buffer+48+100, 0, 0xbfffffff - (int)(buffer+48+100)); // LD_* eraser // 40 : extra space for memset function memset(buffer-3000, 0, 3000-40); } | cs |
문제를 보니 상당히 긴 코드가 나온다.
RTL Chaining에 대해 공부를 했기 때문에 문제 출제 의도를 쉽게 파악할 수 있었다.
이 기법을 간단히 설명하자면
RTL이라는 기법을 응용하여 함수의 호출을 연계하는 것이다.
이 문제를 풀이할때 이 기법을 사용할 수 밖에 없는데 그 이유는 문제를 분석하면서 알 수 있었다.
- main() 에서 모든 argv[1]의 값에서 '\x40'을 검사하여 예외처리 시킨다.
- addr에 &DO의 주소를 넣고 argv[1][44] 부터 4byte 즉, ret의 값이 &DO인지 확인하고 아닐시 예외처리 한다.
- 이후 strcpy()의 사용으로 인해 bof가 터진다.
- memset()로 buffer와 argv[1]의 모든 주소값을 0으로 세팅한다.
- LD_PRELOAD 로 인한 후킹도 memset()를 이용하여 방지한다.
이제 함수를 연계적으로 호출하기 위해 각 함수의 주소를 gdb로 구해줬다.
각 함수의 주소를 구했으니 세그폴트가 뜨는지 확인해보았다.
예외처리에 걸리지 않고 잘 실행이 된다.
이제 마지막으로 호출한 DO의 인자값으로 /bin/sh을 넘겨주면 되는데
인자값이 넘어가는 부분에 BBBB를 넣고 주소를 확인한 뒤
core 파일을 확인하였다.
/bin/sh이 들어간 주소를 인자로 넘겨야하기 때문에 페이로드 구성을 아래와 같이 하였다.
`python -c 'print "dummy(44byte)" + "&DO" + "&GYE" + "&GUL" + "&YUT" + "&MO" + "/bin/sh이 들어간 주소" + "/bin/sh"'`
따라서 /bin/sh이 들어간 주소는 0x42424242가 들어간 주소 + 4의 주소이고
바로 다음 /bin/sh을 넣어주면 된다.
core 파일에서 /bin/sh이 들어간 위치는 0xbffffa68 이다.
따라서 익스를 하면..!
쉘을 띄울 수 있다.
반응형