1. 시작하기에 앞서서
ASLR - Address Space Layout Randomization
ASLR은 기본적인 메모리 보호 기법 중 하나로, stack 영역이나 data, heap 영역에서 실행을 하거나 함수를 호출할 때 주소값을 랜덤으로 변경함으로써 기존에 사용하였던 기본적인 BOF 기법을 사용하지 못하게 하는 역할을 한다. 이때는 앞에 사용했던 RET 변조 기법을 사용하지 못한다.
NX bit
NX는 Non-executable의 약자로, 말 그대로 어떤 프로그램이 조건에 걸리면 실행되지 않도록 한다는 의미이다. 따라서 NX bit는 buffer overflow를 적용할 수 있는 메모리 영역에 있는 프로그램이 실행되지 않도록 하는 보호 기법이다.
위의 2개의 기법을 모두 우회하기 위한 기법을 Return Oriented Programming이라고 하는데, 이를 설명하기 위해서 배우는 기법 중 하나가 RTL 기법이다. 그럼 시작해볼까?
2. 개요
RTL 기법은 위에서 언급한 NX bit를 우회하기 위해 만들어진 기법이다. 이 기법에서 사용하는 영역은 이미 메모리에 내장되어 있던 라이브러리인 libc이다.
libc 라이브러리는 메모리 상에 내장되어 있지만, 위의 사진처럼 자신의 바이너리에 있는 같은 libc 파일을 다운로드받아 pwntool을 사용하여 그 파일을 불러올 수 있다. RTL 기법은 바이너리에 shell을 따기 위한 함수가 거의 없을 때 유용하게 사용한다.
2. RTL exploit의 원리
libc의 주소는 변하지 않으므로 이 라이브러리에 있는 함수를 가져다 쓴다면 문제가 되지 않는다. 우리는 system 함수의 인자에 "/bin/sh"이라는 문자열을 넣어 쉘을 실행시킬 것이다. 함수에서 return address를 libc의 System 함수로 변조하면 된다. 따라서 exploit code를 작성하면 다음과 같다.
./(binary) `python -c 'print (buffer+더미+sfp)+(ret자리에 system주소)+(더미 4byte)+("/bin/sh"의 주소)'`
* 여기서 더미 4byte는 system함수를 호출하는 방식에 의해 존재하는 것이므로 설명하지 않겠다. RTL 기법에서는 system함수 이외에 호출하는 함수가 없으므로 의미 없는 값을 채운다. 이곳에 어떤 주소를 넣어 system함수 이외에 자신이 호출하고 싶은 함수를 연속적으로 호출할 수 있도록 하는 기법이 등장하는데, 이것이 RTL Chaining 기법이다. 추후에 설명하도록 하겠다.
3. 바이너리 예시
#include<stdio.h> int main() { char buf[120]; read(1,buf,200); write(0,buf,120); return 0; }
여기서 exploit 코드를 작성한다고 하면, 120byte와 sfp의 총 124byte + libc의 system 주소 + dummy 4byte + "/bin/sh"의 주소일 것이다. "/bin/sh"의 주소는 주어질 수도 있지만, 주어지지 않았을 때 libc에 따른 offset을 구하는 방법이 있으므로 아직까진 걱정하지 않아도 된다.
그럼, rtl의 기본 원리는 끝났다. 이제 제대로 된 Pwnable의 세계로 들어가보자.