즉, {str 배열 + sfp ( 260바이트 )} 에 쉘코드를 넣고 {RET 주소 ( 4바이트 )} 에 str 배열 주소를 덮어씌우면 main 함수가 return 하고 쉘코드가 위치한 str 배열로 점프하면 쉘을 획득할수 있다.
그러나, gdb 를 이용해 테스트을 해보면 RET 주소까지 덮여있지 않은것을 볼 수있다.
이것은 각 시스템마다 메모리를 할당하는 단위가 있는데 단위를 맞춰주기 위해서 256 바이트를 정확하게 맞혀서 할당하는것이 아니라 조금 넉넉하게 264바이트를 할당한 것이다.
예를들어, 이 시스템은 메모리를 할당할 때 단위가 24바이트이다. 그러면 256 바이트를 할당하기 위해서 8바이트 패딩을 넣고 총 (24 * 11 = 264) 바이트를 할당하는 것이다.
마지막으로, str 의 (시작)주소를 알아내고, {str(264바이트) + sfp(4바이트) + RET(4바이트)} 에 맞게 페이로드를 작성하면 exploit 을 성공 할 것이다.
Segmentation Fault 이유는 간단하다. 다시 gdb 를 이용해 str 의 주소를 확인해보면 달라져있다.
이것은 ASLR 이라는 메모리 보호기법인데, 메모리 주소가 항상 고정적이면 해커가 그 주소만 알아내면 쉘코드를 넣기도 쉽고 페이로드 작성하기도 훨씬 수월하여 이를 보호하기 위해 스택주소를 랜덤하게 할당하는 기법이다.
ASLR 을 우회하기 위해서는 attackme 프로그램에서 로드되는 스택 메모리를 사용하지 않고 다른 공간을 할용해야한다.
gdb 를 이용해 스택의 가장 높은주소로 가보면 시스템의 환경변수와 함께 메모리에 로드되어 있습니다. 또한, 매 실행마다 그 환경변수의 주소 값은 변하지 않는다.
환경변수들의 주소값이 변하지 않는 이유는 정확하게는 모르겠지만, 사용자가 사용할 수 있는 스택의 범위는 정해져있고, 환경변수들은 가장 높은 주소에 위치해 있어 가장 먼저 로드되고 스택은 거꾸로 자라기 때문에 상대적으로 낮은주소에 있는 코드영역이나 데이터영역에 있는 주소값들이 랜덤하게 변하는것으로 추측 된다.
그렇다면, 환경변수에 쉘코드를 넣고 RET 주소에 쉘코드가 위치한 환경변수의 주소값을 넣으면 exploit 을 할 수 있다.