OverTheWire_Wargame Narnia

[ level6 -> level7 ]


Level7입니다. Narnia도 끝이 다가오네요.

코드를 보면 처음에 fp라는 이름의 int형 포인터에 puts함수의 주소를 넣어줍니다.

이는 곧 fp를 함수포인터로 사용한다는 의미가 되겠네요. 인자는 puts와 동일한 (char *)형입니다.

그리고 환경변수와 argv[3] 이후의 값들을 모두 제거하네요.

다음으로 취약점이 발생하는 strcpy문이 2번 호출됩니다. b1와 b2에 argv[1]와 argv[2]를 덮어씌워주는데, b2가 b1보다 나중에 선언되기 때문에 b1이 high address가 되겠네요. 따라서 b2에서 buffer를 overflow 시키게 된다면 b1의 값에도 영향을 미칠 것입니다.

그리고 esp의 값을 0xff000000과 and 시켜 결국 fp의 값이 스택 영역일 경우 프로그램을 종료시킵니다. 이는 스택에 쉘코드를 직접 넣어 실행 시킬 경우를 막아놓은 장치인듯 합니다.

마지막으로 b1을 인자로 fp(puts) 함수를 호출시킵니다.

대충 감이 오지 않나요? 일단 한번 실행을 해 보겠습니다.



b1과 b2의 값을 변경시켜가면서 출력을 해 봤더니 b1의 값이 8바이트 이상 입력 될 시 segmentation fault가 나타나는 것을 확인 할 수 있습니다.

b2의 값은 overflow 시켰을 때 16바이트를 입력하면 segmentation fault가 일어나는 것으로 보아, b1과 b2 사이에 dummy byte는 따로 없는 것 같습니다.

그렇다면 여기서 생각 할 수 있는 것은 b1[8]의 상위 스택에 바로 sfp, ret가 있거나 다른 경우의 수가 있다는 것입니다.

하지만 이 코드의 경우 gdb로 분석 해봤을 때 exit(1)로 끝나는 코드이기 때문에 leave;ret이 없는 것으로 보아 첫 번째 경우는 제외하였습니다.

그럼 두 번째 경우를 알아봐야 하는데, gdb를 통해 알아보도록 하겠습니다.



main 함수를 disassemble 한 상태입니다. 코드의 처음 부분에서 지역변수를 위해 0x30만큼 esp를 확보 해 준 이후 곧바로 esp+0x28의 값에 0x80483f0를 넣어줍니다.

????? 왜죠? 분명 선언은 b1, b2, fp, i 순으로 했는데...

아직 시스템에 대한 공부가 부족해서 정확하게 이해는 하지 못했습니다. 정황상으로는 선언과는 별개로 값을 직접 입력 해 줄 때에는 순서와 상관 없이 직접 입력 해 준 변수가 가장 상위의 스택에 쌓이는 듯 합니다.

아, 그리고 0x80483f0의 값은 puts@plt의 주소입니다. 결국 i, b2, b1, fp 의 순서로 스택이 나열되어 있다는 뜻이 되겠습니다.

그림에는 따로 나와있지 않지만 b1의 주소는 esp+0x20, b2의 주소는 esp+0x18입니다.

드디어 두 번째 경우의 수를 찾아냈습니다.

제가 생각하지 못했던 스택 시스템에 따라 b1 이후에 fp가 저장되어 있기 때문에 b1에 8byte를 입력했을 경우 fp에 NULL이 입력되어 마지막에 fp를 호출 할 때 segmentation fault가 나타났던 것입니다.

그렇다면 puts가 저장 되어 있는 fp에 system 함수의 주소를 꽂아주고, b1에는 b2를 이용해 /bin/sh를 넣어준다면 system("/bin/sh")라는 완벽한 결과가 나타나겠습니다.

자, 갑시다!



address of system : 0xf7e63cd0



system 함수가 정상적으로 실행되는 것을 확인 할 수 있습니다.

b2에 값을 더 추가하여 b1에 /bin/sh를 넣어주도록 합시다.


payload :

./narnia6 'A'*8 + 0xf7e63cd0 + 'B'*8 + '/bin/sh'




짜잔! 깔끔하게 쉘을 얻어냈습니다.


+ Recent posts