-
LEVEL 13WARGAME/FTZ 2018. 4. 27. 16:13
level13 FTZ LEVEL13
[Summary]
- 소스코드의 10 행에서 strcpy 함수를 사용하므로 길이체크를 하지않아 Buffer Overflow 취약점이 발생한다.
- 소스코드의 12 행에서 메모리보호기법 중 canary 역할을하는 i 변수의 값이 변조되면 종료되어 버리기 때문에 i 변수의 값이 변조되지 않은것처럼 그대로 덮어준다.
- buf 배열의 길이가 (1024 + 12) 이며 canary 변수 i의 길이(4 + 8) 와 sfp 사이즈(4바이트)를 더한 1052바이트를 payload 로 전송하게되면 RET 값을 변조할 수 있다.
- aslr 보호기법으로 인해 buf 배열에 shellcode 를 삽입할 수 없어서 환경변수에 삽입하고 RET 를 쉘코드가 포함된 환경변수의 주소로 변조함으로써 결론적으로 프로그램의 흐름을 제어하고 level14(3094) 권한의 쉘을 획득하였다.
[Sourcecode]
1. #include <stdlib.h> 2. 3. main(int argc, char *argv[]) 4. { 5. long i=0x1234567; 6. char buf[1024]; 7. 8. setreuid( 3094, 3094 ); 9. if(argc > 1) 10. strcpy(buf,argv[1]); 11. 12. if(i != 0x1234567) { 13. printf(" Warnning: Buffer Overflow !!! \n"); 14. kill(0,11); 15. } 16. } 17. 18. // attackme.c
[Analysis]
- setuid 가 설정되어 있으면 gdb 가 동작하지 않기 떄문에 tmp 디렉토리에 cp 명령을 이용하여 복사한다.
- attackme 소스코드 9~10행 보면 매개변수가 있을경우 buf 배열에 버퍼를 복사(strcpy)한다.
- 소스코드 상에서는 buf 배열 크기가 1024 이지만 실제로 1024 이상의 버퍼가 할당되어 있을것이다.(자세한 내용 참조 : http://mdkstudy.tistory.com/41)
- 또한, 소스코드 12~15 행을 보면 i 변수에 0x01234567 값이 아닐경우 즉, 변조되었을경우 프로그램을 종료 시켜버리는 루틴이 있다.
- 이제 소스코드를 통해 전체적인 흐름은 파악했으니 gdb 를 이용해 실행시켜보면서 동적 분석을 진행한다.
- gdb 에 실행파일을 로드한 뒤 main 함수의 ret 에 브레이크포인트를 걸고 실행한다.
- buf 배열에 1024 사이즈만큼 "A" 문자열을 넣고 확인해봣더니 예상했던데로 시스템에서 1024 보다 12바이트 더 큰 공간을 할당했다.
- 따라서, 1036(1024 + 12) 사이즈만큼 넣고 실행한다.
- 하지만, SIGSEGV 시그널이 발생하면서 프로그램이 종료 되어버렸다.
- 이유를 파악하기 위해 esp 레지스터 값을 통해 필자가 넣은 문자열을 확인해보니 사이즈는 1036 이 맞지만 문자열의 마지막을 뜻하는 NULL(0x00) 이 자동으로 "A" 문자열 뒤에 들어가버려서 canary 변수를 변조되었다.
- 이를 우회하기 위해, canary 변수의 값과 동일하게 0x01234567 을 넣고 실행했다.
- 실행결과, SIGSEGV 시그널이 발생하지 않고 정상실행되었다.
- 메모리(스택 영역)를 확인해보니 canary 변수주소의 값이 변조되지 않은것처럼 보인다.
- 따라서, 이 가설을 통해 canary 변수의 값을 그대로 덮어주면 우회된다는것이 증명되었고 payload 를 canary 변수 이후 12바이트를 더 덮으면 RET 주소도 변조할 수 있게 되었다.
- gdb 를 통해 다시 paylaod 를 작성한 뒤, 실행시켜보면 RET 가 "CCCC" 문자열로 변조되었는것을 확인할 수 있다.
- Shell 로 빠져나와 bash2 프로세스를 실행시키고(자세한 내용 참조 : http://mdkstudy.tistory.com/42) aslr 기법을 우회하기 위한 환경변수에 쉘코드를 로드한다.
- findegg.c 를 통해 필자가 로딩한 환경변수의 주소를 찾고 gdb 에서 확인을 한다.
(자세한 내용 참조 : http://mdkstudy.tistory.com/42)
- findegg.c 에서 찾은 주소 0xbffffc1f 를 살펴보니 필자가 올린 쉘코드가 위치한 환경변수의 주소가 맞다.
마지막으로, payload 는 (의미없는 값 * 1036) + canary(\x67\x45\x23\x01) + (의미없는 값 * 12) + 쉘코드가 위치한 환경변수 주소(\x1f\xfc\xff\xbf) 이렇게 작성하면 된다.
[Exploit]
./attackme $(python -c 'print "A"*1036 + "\x67\x45\x23\x01" + "B"*12 + "\x1f\xfc\xff\xbf"')
[References]