문제분석 & 풀이
○ 코드 분석
1. str[256] 선언
2. setreuid()를 통해 level13 권한으로 설정
4. gets()로 사용자에게 값을 입력받는다.
level11번과 마찬가지로 입력값에 대한 검증을 진행하지 않고 있기 때문에, 버퍼오버플로우 문제라는 것을 직감할 수 있다.
그러나 level11과의 차이점은 level11의 경우 argv[1]을 통해 입력값을 받았지만 이번 문제는 프로그램 시작 후에 입력값을 받고 있다.
따라서 페이로드를 작성할 때 파이프를 사용해야 할 것 같다.
문제로 돌아와서, 페이로드 작성 시를 제외해서는 level11번 문제와 동일하므로 똑같이 진행해보도록 하겠다.
먼저, str[256] 부터 ret 까지의 거리를 알아내기 위해서 attackme를 디버깅해야한다.
따라서 attackme를 tmp 폴더로 복사하여 GDB로 디버깅했다.
asm 코드를 확인했다.
level11 문제와 비슷한 구조이며, str[256]을 위해 264 바이트를 할당하고 있다. (빨간색 부분)
attackme의 스택 구조는 위 사진과 같으며, level11 문제와 동일하다.
이제 eggshell을 실행해서 메모리내에 셸코드를 적재하고 주소를 알아내자.
이 정보를 토대로 페이로드를 작성하면 다음과 같다.
"A"*268+"\xb8\xef\xff\xbf"
attackme 실행시 입력할 값에 대한 페이로드를 작성했으니, 파이프를 이용한 페이로드를 작성해보자.
(python -c 'print "A"*268+"\xb8\xef\xff\xbf"';cat) | ./attackme
필자는 python과 파이프를 이용해서 위와 같이 페이로드를 완성하였다. (페이로드 사이에 cat 이 붙은 이유는 ./attackme 실행 후 값을 입력하고 종료하지 않고 pause 시키기 위해서이다.)
위와 같이 attackme가 실행됐고 pause된 상태에서 my-pass를 입력해봤다.
결과는?
eggshell에서 출력하는 셸코드 주소가 문제가 있다고 판단했다.
eggshell에서는 EGG라는 환경변수를 통해 셸코드를 저장하기 때문에, 환경변수 EGG의 주소를 직접 출력하는 코드를 만들어서 해당 주소가 eggshell 프로그램이 출력한 주소와 같은지 확인했다.
코드를 작성 후 컴파일하고 실행했다.
eggshell에서 출력해준 주소와 다른 주소가 출력되는 것을 확인 할 수 있다.
예상대로 eggshell 프로그램에서 출력한 셸코드의 주소가 잘못되었다는 것을 알 수 있었고 새로운 주소를 통해 페이로드를 다시 구성했다.
(python -c 'print "A"*268+"\xc1\xf2\xff\xbf"';cat) | ./attackme
실행해보자.