ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [LOB] Nightmare -> Xavius Write-up
    표튜터와 함께하는 Pwnable/The Lord Of the BOF Write-up 2019. 3. 19. 23:51

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



    이번문제는 음.. 어려웠당... 우선 코드를 보자

    스택(0xbf...) binary_image(0x08...) 라이브러리


    이번 문제의 코드를 보면 스택영역과 바이너리영역을 모두 사용할 수 없다.

    leave와 ret gadget을 이용할 수도 없고 이 의미는 라이브러리 함수가

    leave와 ret로 끝나므로 라이브러리도 사용할 수 없다는 뜻이다.

    그렇다면 이 문제는 대체 어떻게 푸는 것일까??하는 생각이 들었다..

    ret를 제외한 모든 부분이 초기화되기 때문이다..



    이전 문제들과 달랐던 점은 fgets()을 이용해서 인자를 받는다.

    그리고 라이브러리 함수를 사용하지 못하게 하는 방법은

    다른 조건들 처럼 0x40를 확인하면 되는데 왜 굳이 0x90를 비교하는 방법을 사용했을까??


    이 부분들이 이 문제를 해결하는 키워드이다.

    또한 라이브러리 함수를 사용할 수 없으니 쉘코드를 사용해야겠다는 생각이 들었다.

    쉘코드를 저장할 곳을 생각해보니 스택은 ret를 제외하고 모두 0으로

    초기화되기때문에 스택에는 저장할 수 없었다. 

    그렇기 때문에 쉘코드를 저장할 공간을 찾아야했다.



    우선 메모리 맵을 통해 우리가 사용할 수 있는 지점을 예측해보기로 했다.

    fgets 함수는 stdin(표준입력)으로 입력을 받는데 

    stdin에는 버퍼가 존재하며 이 버퍼는 flush처리를 하지 않았다.

    이말은 우리가 fgets으로 입력을 했을 때 입력한 값이 남아있을 수 있다는 것이다.


    fgets(buffer, 256, stdin)을 해석하면

    stdin파일에서 256Byte 만큼 읽어 buffer에 저장한다는 의미이다.

    또한 fgets를 이용하여 입력을 하면 입력한 값은 _IO_FILE_Structure에 저장된다.



    이 _IO_FILE은 /usr/include/libio.h에 정의되어있다.


    get area는 입력버퍼를 의미하며

    위에서부터 flag, 현재 읽어야할 위치, 입력버퍼의 끝, 입력버퍼의 시작점을 의미한다.

    그러므로 stdin으로 넘겨진 데이터는 입력버퍼의 시작과 끝에 공간에 존재한다는 것을 알 수있다.

    (fgets가 실행되고나면 버퍼를 읽었기 때문에 현재읽어야할 위치와 입력버퍼의 끝은 같아지게된다.)


    이제 fgets가 리턴할 때 어떤식으로 관리되는지 알아보자

    1. 리턴하기 전 stdin의 입력 버퍼 데이터를 초기화해주고 리턴하는 것인가?

    2. 퍼미션으로 제어를 하는 것인가?


    _IO_FILE 구조체는 fgets에서 인자로 넘어온 것이 전부이기 때문에 fgets와 관련이없다.

    또한 fflush(), rewind(), while(getchar() != '\n'); 들이 입력 버퍼 초기화 방법으로

    알려져있지만 이는 입력 버퍼 자체를 초기화시키는 방법이 아니다.

    이 방법들은 _IO_FILE의 현재 읽어야할 위치값을 입력버퍼의 끝을 나타내는 값과

    동일하게 만드는 역할일 뿐 입력버퍼를 초기화하는 작업을 하지는 않기 때문이다.


    진짜 초기화를 하고싶다면 직접 stdin 파일기술자를 이용하여 데이터를 덮어쓰는 방법과

    memset()을 이용하는 방법이 있다.



    어쨌든 fgets는 퍼미션으로 제어하는게 맞다.

    실행권한이 없더라도 고정된 위치에 data가 남는다는 의미이며

    이를 이용해 파라미터를 넘기는 것으로 활용할 수가 있다.

    때문에 우리가 입력한 값은 초기화 되지않고 

    고정된 입력버퍼 공간에 남아있다는 점을 이용할 수 있는 것이다!!



    fgets 함수를 실행시키고 aaaabbbb를 입력해보았다.

    fgets의 전달인자에 해당하는 stdin의 값이 0x8049a3c 였고

    stdin 구조를 보니 위에서 설명한대로 flags, _IO_read_ptr, _IO_read_end, _IO_read_base 가 보였다.

    그렇다면 0x40015000이 stdin의 입력버퍼의 시작이기 때문에

     이곳에 우리의 입력값이 남아있을 것이다.



    우리가 입력한 "aaaabbbb"를 확인할 수 있었다. 그렇다면 우리가 활용할 수 있는

    공간을 찾았다. 0x40015000을 이용하여 쉘을 따보도록 하자.



    Payload는 다음과 같다.

    Payload = Nop(19) + Shellcode(25) + 0x40015000


    * 사용된 Shellcode *

    "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"




    쉘이 따졌다. 복사본이 아닌 원본에도 진행해보자~



    마찬가지로 쉘이 따졌다!!


    마지막 문제로~~



    참고 : https://umbum.tistory.com/286


    댓글 0

Designed by Tistory.