ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [LOB] Goblin -> Orc Write-up
    표튜터와 함께하는 Pwnable/The Lord Of the BOF Write-up 2019. 2. 9. 00:33

    혹시나 이상하거나 잘못된 것이 있다면 댓글 부탁드립니다.


    이전까지의 문제들은 전에 풀어봤던 문제들과 비슷해서 너무나 쉽게 풀렸다.

    그래서 살짝(?) 자만했는데 이번 문제에서 뚜두려맞았다ㅋㅋ

    egghunter라는 개념이 필요했다. 그래서 인지 꽤 오랜시간 삽질을 했던 것 같다.



    소스코드를 보자!

    우선 40크기의 버퍼를 주어줬고

    egghunter라는 부분이 있다.

    이 부분은 환경변수의 값을 0으로 초기화시키기 때문에

    이전까지 써왔던 환경변수를 이용한 eggshell을 사용할 수 없게 만든다.


    또한 그 아래에는 argv[1]의 47번 배열 즉, 48번째의 배열의 값이 "\xbf"가

    아니면 "stack is still your friend라는 문구와 함께 프로그램이 종료된다.

    이 부분에서 알 수 있는 것은 아마도 buf 크기 40 + sfp(4) + ret(4)로 

    ret가 \xbf 로 시작하게 될 것임을 짐작 할 수 있었다.






    문제에는 딱히 어떠한 mitigation이 걸려있지는 않았다.







    본격적으로 문제를 풀어보자

    우선 gdb 사용하기위해서 orc 파일을 복사해주었다.

    우선 분석을 하기 전에 if문의 조건을 맞춰줘서

    어떤식으로 동작하는지 보기로 했다. 

    그래서 breakpoint를 main+146에 걸어보았다.





    어셈블리어코드에서 보면 edx와 0xbf를 비교하였기 때문에

    인자를 제대로 넣었다면 edx에는 내가넣은 "\xbf"가 있을 것이라고 생각했고

    확인해보았다.




    edx에 비교하려는 내가 넣은 "\xbf"가 제대로 들어있는 것을 확인하였다. 

    그렇기 때문에 조건문을 pass했다.





    다음으로는 내가 넣은 인자(argv[1])을 찾아보려고 했다.

    물론 "\xbf"의 위치를 알았으니 당연히 그 이전에 있겠지만

    그래도 찾아보았다.




    strcpy의 인자로 들어있는 값은 buf와 argv[1]이기 때문에

    argv[1]의 주소를 찾아낼 수 있다고 생각했다.

    그래서 이번엔 strcpy전에 breakpoint를 걸어서 argv[1]의 시작주소를 찾아보기로 했다.




    eax에는 복사할 인자의 시작주소 값이 들어있었다.



    그리고 edx값 또는 위에서 찾은 주소를 따라가 보니 내가 넣은 "a"들과 "\xbf"가 보였다.


    eax와 edx 인자를 push하게 되는데

    eax의 주소는 0xbffffaa0으로 바로 buffer의 주소값이다.




    다음의 코드들을 진행해보면 더욱 확실히 알 수 있다.

    argv[1]를 0xbffffaa0(buffer)으로 push 했다.

    그렇게 됨으로 버퍼에 "a"와 "\xbf"가 저장된 것을 볼 수 있었다.





    이제 필요한 것은 다 구했고 마지막으로 쉘코드만 있으면 되는데

    쉘코드는 구글링을 통해 구했다.

    shell-storm이나 shellcraft를 이용하면 좋다!





    공격방식은 이렇다.

    우선 입력해주는 인자에 쉘코드를 넣고

    nop sled로 남은 부분을 채워주고 마지막 ret값을 버퍼의 주소로 넘겨주면

    스택 버퍼오버플로우가 일어나면서 main의 ret를 버퍼의 시작주소로 넘겨버린다.


    그렇게 되면 쉘코드가 동작하면서 쉘을 딸 수 있게 되는 것이다.




    입력한 payload는 다음과 같다.

    24Byte의 쉘코드와 20개의 nop 그리고 ret(버퍼의 시작주소)

    1
    2
    3
    ./orc `python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "\x90"*20 + "\xa0\xfa\xff\xbf"'`
     
     






    엥? 하지만 쉘이 제대로 넘어오지 않았다...?!





    그 이유는 바로 gdb를 이용하여 디버깅하는 것은

    어딘가에 한번 옮겨진 뒤 분석을 하는 것이라

    동적으로 움직이는 실제 프로세스의주소와 GDB로 디버깅한 주소에

    차이가 생긴다고 한다.



    그러므로 orc.c의 코드에 다음과 같은 줄을 추가하여




    주소값을 알아낸 뒤 payload에서 ret만 바꾸어주면 해결된다.



    쉘이 넘어왔다.

    하지만 이 방법은 코드를 알고 있을 때나 가능하다 

    즉, 코드를 주어주지않으면 저 방법은 쓸 수 없다는 것이다.

    이걸 해결하려고 고민하던 중

    "동적으로 움직이는 실제 프로세스의주소와 GDB로 디버깅한 주소에

    차이가 생긴다고 한다."

    이것을 해결할 방법을 알아냈다.





    그것은 바로..

    복사할 때 파일명의 길이를 같게 해주면 주소값에 변화가 없다는 것이다.

    Thanks to Circler !!




    그래서 그냥 다시 복사했다^^




    복사한 뒤 기존의 주소로 payload를 진행해서 core파일을 dump하였다.

    core파일을 분석해서 제대로 주소값을 찾았다!

    사진에서 볼 수 있듯이 쉘코드의 시작이 있는 곳이 바로 버퍼의 시작주소다.

    0xbffffd50





    또 다른 방법!!





    방법2. 굳이 버퍼 시작주소값을 ret에 주지 않아도 된다.

    다른방법은 생각보다 간단하다.

    바로 ret 다음주소를 넘겨주는 것이다.

    Payload 구성은 다음과 같다.

    "a"*44  +  "ret 다음주소" + 쉘코드 + "\x90"

    "\x90"을 넣는 이유는 혹시 쉘코드 실행에 방해되는 문자열이 들어갈까봐 넣었다.

    (안넣어도됨)




    다음 문제로~











    반응형

    댓글

Designed by Tistory.