#About


[그림 1] - xavius.c 소스 코드 확인




#Solution


[ + ] 소스 코드 해석


1. buffer라는 변수에 40바이트 및 포인터 변수 ret_addr 할당


2. fgets 함수를 통한 buffer로부터 256바이트를 받아 stdin에 복사 후 buffer 출력


3. 조건문을 통해 ret의 마지막 바이트가 \xbf 또는 \x08을 막음으로써 스택 영역 및 바이너리 영역으로 리턴 불가


4. memcpy 함수를 이용, ret 주소 4바이트를 복사 후 ret 값 중 2바이트가 \x90\x90일 때 까지 반복 및 leave-ret 사용 불가


5. memset 함수를 이용, 입력 buffer 및 ret 이후의 공간, LD_*를 막기 위한 buffer아래로 3000바이트 모두 초기화




해당 문제는 buffer 및 LD_환경변수, leave-ret 영역 등 현재까지 문제를 풀어 옴에 있어 사용하던 공간을 모두 사용할 수 없다


하지만 여지껏 strcpy 함수를 이용하여 strcpy(buffer, argv[1])와 같이 사용해오던 것과는 달리 fgets 함수를 이용한다


 fgets 함수에서 사용되는 stdin은 임시 입력 버퍼로써, stdin으로 입력을 받을 경우 임시 입력 버퍼에 저장이 된다


이 때, getchar 함수와 같은 것으로 임시 입력 버퍼를 초기화 해주어야 하지만 해당 코드에서는 초기화 되지 않음을 알 수 있다


이는 메모리 어딘가에 임시 입력 버퍼의 값이 남아 있다는 말이므로 stdin에 저장 된 입력 버퍼의 위치를 찾아야 한다


[그림 2] - 디스어셈블링을 통한 stdin 구조체 주소 값을 가리키는 주소 확인


이 후 저장 된 값을 확인하기 위해선 임의의 페이로드 입력이 필요하므로 fgets 함수가 실행 된 후에 중단점을 걸고 임의의 페이로드를 입력해주었다


[그림 3] - stdin의 시작 확인


stdin 객체 <_IO_2_1_stdin_>은 _IO_FILE type이며 _IO_FILE은 /usr/include/libo.h에 정의되어 있으며 구조체는 다음과 같다



struct _IO_FILE { int _flags; /* High-order word is _IO_MAGIC; rest is flags. */ #define _IO_file_flags _flags /* The following pointers correspond to the C++ streambuf protocol. */ /* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */ char* _IO_read_ptr; /* Current read pointer */ char* _IO_read_end; /* End of get area. */ char* _IO_read_base; /* Start of putback+get area. */ char* _IO_write_base; /* Start of put area. */ char* _IO_write_ptr; /* Current put pointer. */ ... }


위 _IO_FILE의 구조와 메모리 값을 매핑 시켜보게 되면 아래와 같다


_flags = 0xfbad2288

_IO_read_ptr = 0x4001502d

_IO_read_end = 0x4001502d

_IO_read_base = 0x40015000

_IO_write_base = 0x40015000

_IO_write_ptr = 0x40015000


주석을 살펴보면 0x40015000부터 입력 값이 저장되는 영역임을 알 수 있고 해당 영역을 살펴본 결과 임의로 입력해주었던 페이로드를 확인할 수 있다 


[그림 4] - 임시 입력 버퍼 주소 확인


이를 통해 buffer에 NOP과 셸 코드를 담고 RET 주소를 0x40015000으로 덮어 씌워 주면 문제를 해결할 수 있음을 알 수 있다


[그림 5] - 셸 획득



+ Recent posts