728x90
int main(int argc, char *argv[]) {
    char buf[0x40] = {};

    initialize();

    read(0, buf, 0x400);
    write(1, buf, sizeof(buf));

    return 0;
}

해당 프로그램은 32비트 환경이고, buf의 크기보다 입력을 많이받아 bof가 일어나지만 NX와 내부 함수에 원하는 함수가 없기 때문에 곧바로 쉘을 딸 수 없습니다. 따라서 직접 쉘에 접속을 해주어야 하는데, 이때 ROP라는 기법을 사용합니다. 

 

#include <stdlib.h>

int system(const char *string);

해당 코드가 system함수의 원형입니다. include하는 부분은 자세히 다루지 않고 전달 인자를 봅시다.

system 함수는 하나의 '포인터'인자를 받습니다. 만약 'ls'라는 명령을 수행하고 싶으면 'ls' 문자열의 주소를 전달해야 합니다. 

물론 직접 프로그래밍하는 입장에선 자동으로 컴파일러가 전달을 해주겠지만, 컴파일러가 없어 수동으로 넣어줘야 합니다. (메모리에 'ls'라는 문자 두개를 넣어준다고 해서 마법이 일어나지 않는다는 말이죠@)

 

또한, 이 인자를 전달을 직접 해주어야 합니다. 우리가 문자열 'ls'와 system함수의 주소를 넣어줘도 둘 사이의 연결고리가 없기 때문에 독립적인 존재입니다. 

 

1. 연결고리?

우선 32비트 환경에선, 인자를 stack에 전달해주면 되기에 pop; pop; pop; ret 이 형태의 gadget을 써주면 됩니다.

64비트 환경에서는 인자가 레지스터에도 들어가기 때문에 pop rdi; ret 이 형태의 gadget을 써야합니다.

 

2. 어떻게 넣어야해

32비트와 64비트는 인자 전달 순서도 다릅니다.

ROP를 기준으로 말하면,  32비트는 "함수 호출 -> gadget -> 인자"이고 64비트는 "gadget -> 인자 -> 함수 호출"입니다. 

 

 

제가 작년에 rop문제를 접하고, 당시에는 워낙 하는게 많아서 반쯤 이해하고 그런가보다 하고 넘어갔었네요. 현명한 선택이였습니다 :D  사실 그 당시에 들었던 의문이 있었는데 ROP나 RTL문제를 풀다 보면 offset을 구해야 합니다. 따라서 libc파일을 주는 경우도 있는데, 어떤 함수는 libc에서 안보이고 어떤 함수는 libc에서 봐야만 합니다. 지금 생각하면 당연한 소리지만, 당시엔 뭔소린지 도통 모르겠고, 정확하게 뭘 모르는지도 몰라 대충 그런갑다 하고 넘어갔죠.

 

3. libc파일이 뭡니까?

아까 위에서 system함수의 원형을 봤는데, <stdlib.h>를 include하는 부분을 넘어갔었죠. 이 부분을 보고 system함수는 라이브러리 함수이구나~ 하는겁니다. include해주지 않으면 쓸 수 없는 함수입니다. 저 stdlib.h파일에 해당 함수가 구현되어 있겠죠.  그래서 문제를 푸실때 puts같은 함수는 그냥 실행파일에서 가져와도 되는데 system함수의 주소는 라이브러리에서 가져와야 합니다. 파일을 주면 거기서 찾고, 아니면 인터넷에서 찾아야죠. (/bin/sh 문자열도 마찬가지입니다)

 

이제 32비트 프로그램을 ROP로 풀어봅시다. 기출문제를 풀어보면서 공부하는게 짱이에요

 

 

728x90

'pwnable' 카테고리의 다른 글

ROP(64bit)  (0) 2021.03.31
ROP(32bit)  (0) 2021.03.30
보호기법  (0) 2020.11.15
5  (0) 2020.10.16
4  (0) 2020.10.16

+ Recent posts