#About


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




#Solution


[ + ] 소스 코드 해석


1. buffer라는 변수에 40바이트와 정수형 변수 i 4바이트 할당 및 선언


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


3. 조건문을 통해 사용자 입력 값 중 48번째 바이트가 \xbf이라면 stack betrayed you!!를 출력 후 종료


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


이번 문제에서는 if 문의 조건이 argv[1] 영역의 48번째 바이트가 \xbf가 되면 문제를 해결할 수 없으므로 stack 영역을 사용할 수 없고 이를 해결하기 위한 방법으로는 RTL이 있다


Return To Libc (RTL)


RTL은 메모리에 미리 적재되어 있는 공유 라이브러리를 이용해 바이너리 상에 원하는 함수가 없어도 공유 라이브러리에서 원하는 함수를 사용할 수 있는 공격 기법이다. 또한 RTL은 리눅스의 메모리 보호 기법 중 하나인 NX bit(Never Execute Bit)를 우회하기 위해 사용되는 기법이다. NX는 스택 세그먼트의 실행 권한을 제한함으로써, 스택에 셸 코드를 삽입하고 실행시키는 것을 방지하기 위한 메모리 기법에 해당한다



라이브러리는 함수가 시작되기 전, 미리 적재 되므로 아래와 같이 중단점을 걸어주고 셸을 실행시키기 위한 함수 중 system 함수의 주소를 확인했다


[그림 2] - system 함수가 위치하는 주소 확인


또한 system 함수를 실행하기 위한 인자인 /bin/sh를 전달시키기 위해, 해당 문자열이 위치하는 주소를 아래와 같이 C 코딩을 통해 확인할 수 있었다


[그림 3] - /bin/sh이 위치하는 주소 확인


위 과정은 어디까지나 system 함수 내에 /bin/sh라는 문자열이 존재하므로 사용할 수 있고, 존재하지 않는다면 전달 인자로 셸 코드가 담긴 


환경변수의 시작 주소와 같은 방법을 사용할 수 있다 위 과정을 통해 셸을 실행시킬 system 함수의 주소와 그에 필요한 인자인 


/bin/sh의 주소를 확인 했으니 페이로드를 작성 하기전 메모리 구조를 생각해보면 다음과 같다


| buffer (40) | SFP(4) | RET(4) | argc |


위 메모리 구조와 찾은 주소 값을 조합하여 페이로드를 작성하였을 경우 아래와 같은 페이로드가 된다


| 임의의 값 (44byte) | &system() (4) | Dummy (4) | &"/bin/sh" (4) |

[ 페이로드 ] - 1


 RET 주소에 system 함수가 위치하는 주소를 넣어주었으며, RET 명령이 진행되면 다음 4바이트인 Dummy부분이 


system 함수의 RET이 되며 따라서 &system+8이 system 함수의 인자가 위치하는 주소가 된다


[ 페이로드 ] - 1을 참조하여 아래와 같이 페이로드를 작성해주었으며 darkknight 권한의 셸 획득을 확인할 수 있었다


[그림 4] - darkknight 권한의 셸 획득


하지만 RET+4 부분의 "DDDD"는 system 함수의 리턴 값이 담기는 부분이라 했으며 문제를 해결함에 있어 목적은 셸을 띄우는 것이기 때문에


셸을 띄움에 있어 문제가 되지 않지만, system 함수의 리턴 값이 올바르지 않으므로 프로그램의 정상 종료가 이루어지지 않는다.


 따라서 system 함수의 리턴 값이 담기는 부분에 종료를 의미하는 exit() 함수의 주소를 적어주게되면 


정상적으로 프로그램을 끝낼 수 있으며 이 과정을 포함한 bugbear의 셸을 획득하는 과정은 아래와 같다


[그림 5] - exit 함수 주소 확인


system 함수의 주소를 확인하는 과정과 동일하게 진행해주었으며 exit 함수의 주소인 0x400391e0을 "DDDD"부분에 대체해주었다 


[그림 6] - 셸 획득




[ + ] RTL의 구체적인 원리 설명 


스택구조가 [ buffer ] [ SFP ] [ RET ]과 같은 형식으로 있다고 가정한다. call 함수를 이용해 정상적으로 system 함수를 호출할 때 


함수 호출 이후 코드 실행을 위해 saved eip를 스택에 push한다 하지만 RET을 이용한 함수를 호출하면 push eip가 진행되지 않은 상태에서 


함수 내부에서 함수를 빠져나올 때 push eip가 되어 있어야 될 위치의 값을 호출하기 때문에 [ &system ] [ &exit ] [ /bin/sh ]와 같은 구성이 가능하며 


함수 인자를 EBP+8 부터 참조하는 것도 이러한 이유 때문이다 또한 이러한 원리를 계속 이용하는 것이 RTL Chaining이다

출처 : http://xer0s.tistory.com/23



+ Recent posts