Dork's port

FTZ Level18 Write-up(FTZ Level18 풀이) 본문

Hackerschool FTZ Write-up

FTZ Level18 Write-up(FTZ Level18 풀이)

Dork94 2018. 3. 26. 03:59

안녕하세요!


문제 18번 입니다!


이번 문제는 조금 특별한 문제이네요!


BOF가 아닌...


BUF이네요! 


즉, 버퍼를 오버시키는 것이 아닌 버퍼를 언더 시키는 것이 목적인 문제 였습니다!


같이 문제를 보도록 하죠!


힌트 부터 무지막지하게 기네요. 


Key는 check의 값을 deadbeef로 만들면 shellout함수가 실행되며 권한 상승이 이루어 집니다!

여기서 당황 했네요.


길게 장황하게 적어져있지만 결국엔 입력을 하나 받아 1크기(char)만큼 x의 주소에 담는 scanf같은 함수입니다.


다른점이있다면 이건 하나씩 루프가 진행되며 string에 담는 다는 것 정도 일까요?

x의 값이 \r또는 \n 그러니까 개행 문자이면 그냥 \a를 출력하고 끝나네요!


위의 값에 대해 잘 모르시는 분들께서는 Crarriage Return 및 Line Feed를 검색해 보시길 바랍니다! 


간단히 말하면 입력 버퍼의 위치를 처음으로 돌리고 한칸 내려주는 명령이에요 :)


그리고 값이 0x08이면 count값을 하나씩 빼주네요!


이때 count는 배열의 위치를 참조하는 변수로 사용됩니다!


이도 저도 아니면 값을 버퍼에 입력하네요!


조금 복잡하죠?


걱정마세요! 어셈블리 코드는 더 복잡하니까요 ㅎㅎ


x = 키보드에서 입력한 한 글자를 저장하는 변수


count = string배열에서 위치를 참조하는 변수


string = 키보드에서 입력받은 문자열을 저장할 변수


이 정도가 될 수 있겠네요! 


그럼 주소를 알기 위해서 Asm을 보도록 하죠!

간단히 찾은 주소는 값 비교를 하면 98주소입니다.


그렇다면 저 주소는 check이겠네요!

그리고 count와 string의 주소를 알아야 하는데 소스코드에서 사용하는 곳을 보면 아래와 같습니다.


 
                  switch(x)
                   {
                      case '\r':
                      case '\n':
                        printf("\a");
                        break;
                      case 0x08:
                        count--;
                        printf("\b \b");
                        break;
                      default:
                        string[count] = x;
                        count++;
                        break;
                 }

스위치 문을 찾아야하는데 저의 경우 키포인트를 count -- 와 count ++로 잡았습니다!


특정 변수를 decl하거나 incl하는 부분을 먼저 찾았어요!


그러면 아래와 같은 코드가 나오게 되는데 대충 비슷해보이네요.


어떤 주소값을 뺀 후 printf를 실행하고 밑에서 마찬가지로 같은 주소를 incl를 하는 것을 보아하니 저 주소가 count의 주소 이겠네요!


그래서 count의 주소는 0xffffff90!

그럼 string의 주소를 찾아 보도록 하죠!


아래 사진을 봐주세요!


이부분이 string에 특정 문자를 넣는 Asm코드 입니다.


천천히 따라가볼게요 9c의 주소를 eax에 넣고 eax의 값을 04의 주소에 넣네요! 그리고 그값은 최종적으로 <main+526>에서 ecx로 변환되어 


<main+532>에서 사용되는 것을 볼 수있네요!


나머지 변수들과 함께 정리를 해볼게요 표시한 곳을 천천히 따라가 보세요!


0xffffff9c -> eax -> 0xffffff04 - > ecx


0xffffff90 -> edx


0xffffff94 -> cl -> 0xffffff03 -> al


이렇게 변환 되네요!


그냥 갖다 쓰면될 것을 귀찮게 말이야


그럼 mov의 명령어를 알맞은 주소로 다시 바꿔본다면 아래와 같이 변환 할 수 있습니다.


mov 0xffffff94(%ebp),(%0xffffff90, 0xffffff9c, 1)


보통 배열을 어떠한 주소에 이동시킬때 (기준포인터, 기준포인터로 부터 쓸 포인터와의 거리, Type Of Buf) 이러한 형식으로 많이 한답니다.


저 부분에 대해서는 직접 배열을 어셈블리언어로 특정 값을 넣는 코드를 짜보시면 어쩔 수 없이 이해가 될거에요!


지금 부분에서 설명을 드리자면 너무 설명이 길어지므로 자중하도록 하겠습니다.


그렇다면 94의 주소는 al인것으로 보아 1바이트 형인 x라는 것을 알 수 있고, 90은 위에서 언급했 듯 count의 주소이므로 하나남은 9c의 주소가 string배열의 첫 시작 주소이겠네요!


스택을 한번 그려 보도록 하죠!


아래와 같이 확정 지을 수 있겠네요! 우리가 해야할 것은 string의 주소로부터 check의 주소까지 가야하네요!


그런데 이렇게 하려면 위로 올라가야하는데(주소를 빼야하는데) 어떻게 입력하는데 뺄 수 있을까요?


답은 switch 문에 있습니다.





배열의 주소를 참조할 수 있는 count주소를 --해주고 있네요! 


그러면 string의 시작주소에서 check의 시작주소까지의 거리는 4바이트 만큼이네요!


 
                      case 0x08:
                        count--;
                        printf("\b \b");
                        break;



그러면 아래와 같이 코드를 작성할 수 있습니다!


허허허헣 이번이 2번째 푸는 건데 처음에 풀땐 당연히 check가 밑에 있겠거니 생각하고 뻘짓했던 기억이 나네요.


심지어 스택을 다 그려놓고는 이럴리는 없다고 제가 잘못했다고 생각하고 다시 고민했죠.


혹시 저와 같은 경험을 하셨다면 앞으로는 자신을 믿으시길 바랍니다! 


마지막을 향해 가고있습니다. 귀귀씽!

Comments