이번에는 함수의 흐름을 FSB로 바꾸는 문제입니다.

exit 함수를 hello 함수로 redirect 시키라고 하네요.



시키는대로 objdump -TR로 exit 함수의 코드 주소를 확인해봅니다.

근데 굳이 이 주소가 아니더라고 GOT를 덮어씌워도 될 것 같습니다.



hello 함수의 주소도 확인해봅니다.


포맷을 4번 출력했을 때 AAAA가 나타납니다.





exit : 0x08049724

hello : 0x80484b4(134513844)


134513844 - 20 = 134513824


(python -c "print '\x24\x97\x04\x08'+'%08x'*2+'%134513824x%n'") | ./format4





이번엔 target을 0x1025544로 바꿔야하네요. 값이 커졌습니다.

포맷을 총 12번 출력 했을 때 AAAA가 나옵니다.




16930116 - 84 = 16930032




이번에는 FSB를 이용해 target을 특정 값으로 바꾸는 문제입니다.



포맷을 총 4번 입력했을 때 우리가 입력한 AAAA를 찾아 낼 수 있었습니다.




4+8*2+44 = 64

값을 64로 바꿔줍니다.



FSB를 이용하여 전역변수인 target을 바꾸는 것이 목표입니다.



objdump -t 를 이용하여 target 변수의 주소를 확인해줍니다.



131번 만큼 포맷을 출력 해주면 우리가 입력한 AAAA가 나타납니다.




이 값을 포맷을 그대로 맞춰서 변경해주면 target 변수의 값이 바뀝니다.



OverTheWire_Wargame Narnia

[ level7 -> level8 ]





level7의 소스입니다. 이전 레벨에서 볼 수 있었던 snprintf 함수의 취약성을 이용한 FSB와 비슷한 듯 합니다.

차이점으로는 main 함수에서 직접 처리하는 것이 아닌 vuln 함수에서 처리한다는 점 빼곤 없어 보입니다. 아, 또 다른 점으로는 buffer 변수의 결과 값을 출력 해 주지 않는다는 점이 있겠습니다. 자, 그럼 실행하면서 어떤식으로 풀어야 할 지 찾아보도록 하죠.



prtf() = 0x80486e0 (0xffffd64c) 부분을 확인 해 보면 괄호 안에 있는 부분은 ptrf 포인터 변수의 주소이고, 왼쪽의 값은 goodfunction 함수의 주소입니다. 이 값을 hackedfunction의 주소인 0x8048706으로 변경하여 shell을 띄우는 게 이번 레벨의 목표인 것 같습니다.

하지만 이전 레벨과 달리 buffer의 변수를 printf로 출력 해 주지 않기 때문에 얼마나 %x 서식문자를 입력 해 주어야 buffer 변수에 접근 할 수 있는지 알 수가 없습니다. 따라서 gdb를 이용해 스택 값을 확인하여 0xffffd64c의 값의 변화를 직접 확인하는 쪽으로 풀이하였습니다. 노가다죠.



vuln 함수에서 snprintf를 한 직후에 breakpoint를 걸어주고 실행하였습니다. 여기서 FSB를 위해 측정한 거리는 다음과 같습니다.


34542 = 0x8706(34566) - 16 - 8

33046 = 0x10804(67588) - 34542


위와 같이 거리를 구한 후 대입 해 주었으나, gdb 상에서 실행하였기에 파일명이 절대경로로 들어가 argv[0]이 변해서 ptrf의 주소 값이 바뀌었습니다. 그래서 그대로 대입을 해 주었으나, ptrf의 값이 바뀌지 않은 것을 보니 %8x를 한 번 사용했을 때는 buffer 변수에 접근을 못하는 듯 합니다. %8x와 거리 값들을 바꿔주변서 계속 시도하다 보면 아래와 같이 ptrf 포인터의 값이 변하는 부분을 찾을 수 있습니다.



%8x를 총 5번 사용했을 때 buffer 변수에 접근 할 수 있다는 것을 확인 할 수 있는데, 이상한 게 한 가지 있습니다.

예상대로라면 buffer 변수에 접근했을 때 ptrf 포인터의 값은 0x08048706이 되어야 하는데, 0x8706은 정상적으로 overwrite 된 반면 0x0804는 0x083c로 들어가 있는 것을 확인 할 수 있었습니다. 원인은 공부가 부족하여 찾지는 못했습니다. 계산법이 틀린건지, 놓친 부분이 있는 것인지는 잘 모르겠습니다. 혹시 아시는 분이 있다면 댓글로 지적 부탁드립니다. :D

일단 답을 찾아내기 위해... 3c에서 04까지의 거리인 0x38(56)을 빼주고 실행해봅시다.



어떻게든 답은 찾아냈습니다. :D

OverTheWire_Wargame Narnia

[ level5 -> level6 ]




자, level5입니다. 문제를 까 보니 i와 buffer 변수가 선언 되어 있으며, i 변수를 500으로 바꾸면 쉘을 띄워주겠다고 합니다.

buffer 변수는 [buffer의 크기-1]의 위치에 NULL을 집어넣기 때문에 overflow는 시키기 어려울 것 같습니다.

그래서 구글링을 잘 해보니 snprintf에 FSB가 존재한다고 합니다. snprintf는 출력 할 때 printf처럼 표준 출력을 사용하지 않고 문자열 자체로 출력하기 때문에 %x와 같은 서식문자도 buffer에 집어 넣을 수 있는 것입니다.

FTZ 이후로 기억 속에서 잊혀져 가던 FSB를 문서를 다시 보면서 어렴풋이 되찾았습니다.

차근차근 실행 해 가면서 보도록 하죠.



먼저 buffer 변수에 문자열을 집어 넣어봤습니다.

버퍼의 총 길이와 입력한 argv[1]의 값을 출력 해 주고, i의 값과 i의 주소를 뱉어냅니다.



여기서 argv[1]에 %x를 입력 해 줍니다.

그러면 snprintf에 의해 %x 문자열 자체가 buffer에 넘어가게 되고, 이를 printf에서 그대로 인자로 전달 해 줘서 %x에 해당하는 인자값을 출력해줍니다.



그럼, AAAA를 인자로 전달하고(printf의 첫 번째 인자) %x를 연달아 쓰면서 해당 인자 값이 몇 번째에 출력 되는 지 확인 해 보았습니다.

%x를 총 5번 사용했을 때 AAAA에 해당하는 값이 출력이 되었습니다.

그럼 이 위치를 이용해 FSB를 시도 해 보도록 하죠.

payload는 아래와 같습니다.


payload :

./narnia5 AAAA+[i의 주소]+%8x%8x%8x%8x+%460c%n


여기서 %460c를 입력 해 준 이유는 앞에 나온 'AAAA'와 i의 주소, %8x의 4번 출력으로 인해 8byte * 5 = 40byte이기 때문에 500에서 40을 빼서 460이 된 것입니다.

또한, i의 주소 앞에 'AAAA'를 붙여주는 이유는 %n이라는 서식문자 자체가 esp+4의 위치(다음 스택)에 있는 주소의 값을 수정해 주기 때문입니다.

그럼 계속 실행 해 보도록 하죠.



앞서 나온 buffer의 크기가 늘어났기 때문에 i의 위치가 변동되었습니다.

0xffffd6dc -> 0xffffd6cc로 바꿔주도록 하죠.



짜잔! key값을 얻어냈습니다.






References

- Format String Bug(HackerLogin 서정현 선배님)

- Format String Attacks(Tim Newsham)

+ Recent posts