#About


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




#Solution


[ + ] 소스 코드 해석


1. 외부 다른 소스파일에 있는 environ 포인터 변수 사용


2. buffer라는 배열에 40바이트 할당 및 정수형 변수 4바이트 i 할당


3. 조건문을 통해 전달 인자가 2개 미만이면 argv error를 출력 후 종료


4. 조건문을 통해 사용자 입력 값의 48번째 바이트가 \xbf가 아닐 시, stack is still your friend.를 출력 후 종료


5. 사용자 입력 값을 buffer에 복사 후 출력


6. memset 함수를 이용해 buffer 40바이트와 SFP 4바이트를 0으로 초기화


7. memset 함수를 이용해 RET 이후부터 0xbfffffff까지 0으로 초기화


6,7번 과정에 해당하는 stack destroyer! 때문에 더 이상 buffer와 argv[0] 등을 사용할 수 없으며 이를 우회하는 방법으로는 

buffer 보다 더 낮은 주소에 위치하는 공유 라이브러리 영역을 사용하는 것이며 메모리 구조도는 다음과 같다


| Code | Data | BSS | Heap | 공유 라이브러리 | buffer | SFP | RET | argc | argv | env | ... | kernel |


공유 라이브러리 영역을 사용하는 방법으로는 LD_PRERLOAD라는 특별한 환경변수를 사용하는 것이다


LD_PRELOAD


프로세스를 실행하는 중에 라이브러리를 로딩할 때, LD_PRELOAD 환경변수가 설정되어 있으면 해당 변수에 지정된 라이브러리를

먼저 로딩하고, 이중 libc 함수명과 동일한 함수가 있다면 해당 함수를 먼저 호출한다. 또한 이러한 특성을 이용해 후킹도 가능하다



먼저, 아무런 동작을 하지 않는 아래의 c 파일을 하나만든 뒤 NOP과 셸 코드를 넣은 이름으로 아래와 같이 컴파일 해주며


컴파일에 사용 된 -fPIC 옵션은 Position-Independent Code의 약자로 동적라이브러리 생성을 위함이며 -shared 옵션은 공유 라이브러리를 만들기 위함이다 


[그림 2] - 공유 라이브러리 영역에 사용할 셸 코드 등록


다음으로 LD_PRELOAD에 아래와 같이 NOP과 셸 코드를 담은 뒤 환경변수에 등록하며 


이 때 주의해야할 점은 프로그램의 절대 경로가 붙어야 오류가 나지 않는다고 한다 


[그림 3] - 환경변수 등록


다음으로 gdb를 이용하여 NOP과 셸 코드가 포함되어 있는 LD_PRELOAD의 시작 주소를 아래와 같이 확인했다


(gdb) r `python -c 'print"\xbf"*48'`

(gdb) x/300x $esp -3000


[그림 4] - LD_PRELOAD 시작 주소 확인


LD_PRELOAD가 시작되는 주소는 0xbffff4d7임을 확인했고 해당 주소를 RET 주소로 아래와 같이 변조해주면 셸을 획득할 수 있다


[그림 5] - skeleton 권한의 셸 획득


아래와 같이 위의 과정을 그대로 하여 셸을 획득할 수 있으며 환경변수의 길이와 프로그램 경로 변경으로 인한 메모리 주소가 변경된다면 


아래의 과정처럼 환경변수와 경로의 길이를 같게 해주어 core 덤프 파일을 분석하면 정확한 RET 주소 즉, LD_PRELOAD의 시작 주소를 확인할 수 있다   


[그림 6] - 셸 획득


[그림 7] - core 덤프 파일 생성


[그림 8] - core 덤프 파일을 통한 LD_PRELOAD 시작 주소 확인


+ 문제를 해결함에 있어 사용 된 셸 코드 


\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff

\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81



+ Recent posts