ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [HackCTF] ROP Write-up
    표튜터와 함께하는 Pwnable/HackCTF Write-up 2019. 4. 24. 00:47

    이번 문제는 ROP이다. 제목 그대로 아주 기본적인 ROP였다.

    그래서 처음 접한다면 어려울 수 있으나 한번이라도 ROP를

    해봤다면 굉장히 쉬운 문제가 될 것이다.




    역시 문제 제목이 ROP라 그런지 Partial RELRO였다. 

    즉, Got Overwrite가 가능했고 NX가 걸려있으므로

    Stack이나 Heap 영역에 실행권한이 없는 상태이다.




    우선 문제를 실행시켜보았다.

    사용자로부터 입력을 받았고 입력 후에는

    "Hello, World!"라는 문자열을 출력해주었다.




    여기까지 진행했을 때 이 입력하는 부분을

    공략하게 될 것이라고 예측했다.





    아니나 다를까 굉장히 친절하게도 이 문제에서는

    대놓고 함수명이 취약한 함수였다ㅋㅋㅋ





    해당 함수를 보니 예상한대로 입력하는 부분이 존재했고

    버퍼보다 큰 값을 입력할 수 있었다. 이 부분에서 BOF를 일으키면

    될 것이라는 것을 알 수 있었다. 그래서 ret의 위치를 찾아보았다.




    ebp로부터 0x88만큼 떨어진 공간의 주소에 입력을 받았고

    0x88이므로 sfp까지 거리가 136임을 알 수 있었다. sfp까지

    덮어야 ret이므로 총 140개의 dummy를 이용해야했다.




    다음으로는 rop진행해야하는데 그러기 위해서는 필요한 것들이 있다.




    크게 3가지로 분류해보았고 하나씩 구해보도록 하겠다.



    1. gadget

    2. rop에 사용될 함수의 plt와 got, offset

    3. "/bin/sh" 저장공간




    먼저 Gadget이다. 아주 간단하게 바이너리에 objdump 명령어를 이용하면 된다.

    운이 좋게 필요한 Gadget이 존재했다. 손쉽게 구할 수 있었다.

    여기서 pop, pop, pop, ret Gadget을 구하는 이유는

    우리가 사용할 함수가 write 함수이기 때문이다. write함수는

    3개의 인자가 필요하고 그 다음으로 read 함수를 사용할 것이기 때문에

    우리는 pppr Gadget을 구하는 것이다.  뒤에서 설명하겠지만

    우리는 이 write함수를 이용해서 read의 실제주소를 구할 것이다.




    두 번째로 rop에 사용될 함수의 plt와 got 그리고 offset을 구해보도록 하겠다.

    역시 마찬가지로 objdump 명령어로 쉽게 구할 수 있다.




    먼저 offset부터 구해보도록 하겠다. 참고로 이 문제 역시

    문제 서버에서 사용하는 libc.so.6 주어줬기 때문에

    이 파일에서 offset을 구해야지 정확히 exploit할 수 있다.



    < write offset >



    < read offset >



    < system offset >





    이번에는 plt이다. plt의 경우 그냥 IDA를 켜면 볼 수도 있고

    gdb(peda)에서 p 명령어로도 구할 수 있다.



    편한 방법을 사용하도록 하자~



     이번에는 got이다. got를 구하는 이유는 got overwrite를 하기 위해서이다.

    got 역시 objdump 명령어를 이용해서 굉장히 쉽게 구할 수 있다.




    마지막으로 system함수의 인자로 사용될 "/bin/sh"의 저장공간이다.

    우리는 "/bin/sh"을 BSS 영역에 저장할 것이다. 그 이유는 바로

    BSS영역은 초기화되지 않는 전역변수들을 위한 영역인데 보통 모든 변수들이

    0으로 초기화되어있으며 주소값이 변하지 않기 때문이다.


    ASLR은 운영체제 레벨에서 진행되며 ASLR이 걸려있어도

    .data, .text, .bss 영역은 고정 주소를 사용한다.


    이렇게 BSS 영역까지 모두 구했으니 Payload를 구성해보도록 하자.





    < Payload >

    Payload의 원리는 다음과 같다. 우선 ret를 write함수로 덮어서 read@got를 leak한다.

    이 때 leak된 read@got는 read 함수의 실제 주소이다.

    ( 참고  : https://xn--vj5b11biyw.kr/123 )




    다음으로는 BSS영역에 "/bin/sh"을 입력할 수 있도록 read 함수를 호출한다.

    인자는 입력을 위해 0, bss영역주소, "/bin/sh\x00"의 길이를 넣어주고 "/bin/sh\x00"를 입력해준다.

     (\x00을 넣는 이유는 혹시나 뒤에 이상한 값이 와서 실행에 문제가 생길 것을 방지하기 위함이다.)




    다음으로는 got overwrite를 진행한다. 우리는 아까 구한 read 함수의 실제주소에서

    미리 구해놓은 read offset을 빼서 libc base주소를 구할 수 있다.

    구한 libc base주소에 system함수의 offset을 더하면 system함수의 실제주소도

    구할 수 있게 된다. 이제 got overwrite를 위한 read 함수를 한번 더 호출해서

    인자로 입력의 0, read@got주소, 주소길이를 주어

    read@got를 system함수의 주소로 덮어씌우는 작업을 한다.




    마지막으로 read함수를 다시 호출하게되면 got overwrite가 진행되었기때문에

    read함수가 아닌 system함수가 호출된다. 인자로는 아까 "/bin/sh"이

    있는 BSS영역의 주소를 주면 system("/bin/sh")이 실행되면서 쉘이 따지게된다.




    Payload를 진행하였더니 FLAG를 볼 수 있었다~!!

    반응형

    '표튜터와 함께하는 Pwnable > HackCTF Write-up' 카테고리의 다른 글

    [HackCTF] Look at me Write-up  (0) 2019.04.26
    [HackCTF] Gift Write-up  (0) 2019.04.25
    [HackCTF] RTL_Core Write-up  (0) 2019.04.23
    [HackCTF] Random Key Write-up  (0) 2019.04.22
    [HackCTF] BOF_PIE Write-up  (0) 2019.04.21

    댓글

Designed by Tistory.