$ cat vampire.c
★char buffer[40]: buffer의 크기가 40바이트. 그럼 buffer(40)+sfp(4)이므로 ret(4)은 45~48바이트
★if(argc < 2): 이번에는 argc == 2일 필요가 없다! 인자를 파일이름 제외 1개 이상 주면 된다.
★if(argv[1][47] != ‘\xbf’): 이번에도 argv[1] 인자에서 48번째 위치에 ‘\xbf’가 있어야 한다. 즉, ret 주소가 있어야 한다.
★if(argv[1][46] == ‘\xff’): 새로운 부분!! Argv[1] 인자의 47번째 원소에 ‘\xff’가 있으면 종료된다. 지금까지 항상 주소가 “\xbf\xff~” 이런 형태였는데 이제는 사용할 수 없다.
★strcpy(buffer, argv[1]); : strcpy 함수는 문자열 길이를 확인하지 않고 ‘\0’을 만날 때까지 buffer에 argv[1]의 내용을 복사한다. 따라서 overflow의 취약점이 있다.
이번 레벨에서는 ret에 넣을 주소에 대해 생각해봐야 한다.
일단, 원래 하던 방식대로 해보자.
임시 디렉터리를 생성해서 cp 명령어로 홈 디렉터리의 원본파일을 생성한 디렉터리에 복사한다.
그리고 ret의 위치를 확인해보자.
(buffer가 40바이트, sfp가 4바이트이므로 ret의 위치는 정확하지만)
sub 0x28, %esp : 스택을 40바이트 확장했다. buffer의 크기만큼 확장한 것을 알 수 있다.
(0x28이 16진수이므로 10진수로 바꾸면 40바이트!)
따라서 buffer 40바이트에는 더미가 붙지 않고 40바이트에 sfp 4바이트가 붙으면
45바이트 위치부터는 ret이 위치한다.
주소가 변하지 않도록 심볼릭 링크 파일을 만들어줬다.
홈 디렉터리에도 원본파일의 심볼릭 링크 파일을 똑같이 만들었다.
공격할 때 사용할 실행파일 이름에 이 vam 파일이름이 들어갈 것이다.
늘릴 수 있는 부분은 "\x90" 부분이어서 이 부분의 크기를 크게 주면 0xbfff 주소에서 벗어날 수 있겠다고 생각했다.
"\x90"*1000000으로 주면 너무 길다고 오류 메세지가 출력되서, "\x90"*100000으로 줬더니 제대로 core dumped 되었다.
생성된 core 파일을 분석해서 ret에 넣을 주소를 찾아보자.
$ gdb -q -c core
(gdb) x/10000x $esp
"\x90"이 100000개가 부족한게 아닌가 생각했었는데
바이너리 형태로 보니까 정말 많다는 것을 알 수 있었다.
주소 영역이 0xbfff에서 벗어나고 0xbffe로 간 것을 알 수 있다.
0xbffe로 주소가 낮아진 이유는 스택은 거꾸로 자라는 성질이 있기 때문이다.
스택 프레임의 크기가 커질수록 스택의 주소가 낮아지는 것이다.
nopsled 기법을 이용해 ret에 임의이 NOP의 주소를 넣어서 shellcode까지 흘러가도록 할 것이기 때문에
NOP 부분의 아무 주소를 선택한다.
0xbffed210이 눈에 딱 들어와서 이 주소를 ret에 넣어보겠다.
이번 레벨은 0xbfff가 아닌 주소만 구한다면 payload 작성은 초기 레벨에서와 같다.
별도의 조건이 붙지 않았기 때문에 argv[1]에서 해결할 수 있다.
(아까 만든 심볼릭 링크 파일을 사용하고)
$ ./vam `python -c 'print "A"*40+"B"*4+"\x10\xd2\xfe\xbf"+"\x90"*100000+
"\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52
\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89
\xe3\x52\x51\x53\x89\xe1\xcd\x80"'`
nopsled 기법을 이용해서 bash 쉘 따기 성공!