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'




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


OverTheWire_Wargame Narnia

[ level3 -> level4 ]




Level3의 문제입니다.

R/W 권한과 READ ONLY의 권한으로 파일을 각각 하나씩 open 해줍니다.

output 하는 경로의 경우 "/dev/null"로 고정이 되어있네요. input의 경우에는 사용자에게 직접 입력을 받습니다. 이 때, 입력은 argv[1]로 받으며 strcpy 함수를 이용하기 때문에 길이 제한이 없습니다. 따라서 이 때 BOF가 발생하게 되는데, ofile은 값을 지정해줬음에도 불구하고 ifile보다 먼저 선언되었기 때문에 ifile에서 32바이트를 넘어가는 길이의 입력을 받을 경우 ofile의 값에도 영향을 미치게 됩니다.

이러한 스택의 특성을 이용하여 level4로 갈 수 있는 패스워드를 따 보도록 합시다.

일단 ifile의 경우 overflow를 시키면 ofile의 값을 덮어씌우게 되는데, 이럴 경우 ofile의 포인터는 overflow 된 ifile의 중간에 위치하게 됩니다. 따라서 아래와 같은 payload를 사용하면 두 개의 파일에 따로따로 접근 할 수 있게 됩니다.




ifle과 ofile을 이어 붙인 그림입니다.

입력을 받을 수 있는 argv[1]에는 ///////////////////tmp/fstr3am_/tmp/fstr3am_/a 를 넣어줍니다.

그럼 첫 번째 fstr3am_ 이후의 위치가 원래 ofile의 시작 포인터입니다. 따라서 ofile을 끄집어 낼 경우 /tmp/fstr3am_/a가 딸려나오게 됩니다.

그리고 ifile을 꺼낼 경우 원래 ifile의 길이인 24byte를 초과했기 때문에 ofile의 마지막인 a 이후에 나오는 NULL Byte까지 인식을 하여 /tmp/fstr3am_/tmp/fstr3am_/a이 ifile의 전체 경로가 됩니다.

그렇다면 /tmp/fstr3am_/tmp/fstr3am_/ 의 경로에 /etc/narnia_pass/narnia4의 symbolic link를 걸어준 a라는 이름의 파일을 생성해주고, /tmp/fstr3am_/ 의 경로에 비어있는 a라는 파일을 하나 만들어주면 /tmp/fstr3am_/a에 level4로 통하는 패스워드가 복사 될 것입니다.



위와 같이 a라는 파일을 두 개 만들어줍니다.



그리고 위에서 설명했던 payload대로 입력을 해 주면 패스워드가 출력됩니다.

+ Recent posts