스택 카나리(stack canary)란?
- 버퍼와 SFP 사이에 임의의 데이터를 삽입하여 버퍼 오버플로우를 탐지하는 기법이다. 에필로그에서 해당 값을 확인하여 메모리가 변조되었는지 확인한다.
위 사진과 같은 형태로 버퍼와 SFP(이전 스택 프레임의 rbp) 사이에 canary 값이 들어가게 되어 메모리 값이 변조 되었는지 확인하는 것이다.
* 스택 프레임 구조를 모른다면 -> https://she11.tistory.com/122 을 먼저 읽어보세요!
canary 직접 확인하기
- dreamhack.io 의 canary 예제 코드를 통해 직접 확인해보자.
먼저, 예제 코드를 이용하여 카나리 옵션이 설정되지 않은 바이너리와 설정된 바이너리를 생성하고 실행한다.
왼쪽 사진은 버퍼가 터져 segmentation fault가 띄워진 것을 확인할 수 있고, 오른쪽 사진은 segmentation fault를 띄우기 전에 canary 값 검증에서 스택 오버플로우가 탐지되어 프로그램이 종료된 것을 확인할 수 있다. GDB를 통해 살펴보자.
두 사진을 비교해보면 빨간 박스로 강조된 부분이 추가된 것을 알 수 있다. 오른쪽 사진을 보자.
<main+8>에서 fs:0x28의 값을 rax에 저장한다.
* fs:0x28 : fs는 세그먼트 레지스터 중 하나이고, 리눅스는 fs를 Thread Local Storage(TLS)를 가리키는 포인터로 사용한다. 이 TLS는 카나리를 비롯한 프로세스 실행에 필요한 여러 데이터가 저장된다. 그래서 리눅스는 프로세스를 실행할 때 fs:0x28에 랜덤 값을 생성한다.
<main+17>에서 fs:0x28 값을 저장한 rax를 다시 rbp - 0x8에 저장한다.
이후 기존의 메인 함수의 흐름대로 코드가 실행된다.
에필로그 직전에 rbp - 0x8 값을 rcx에 저장하고, 이 값을 fs:0x28의 값과 xor 연산을 통해 값이 변조되었는지 확인한다.
변조가 되었다면 __stack_chk_fail 함수가 호출되면서, 프로그램을 종료시킨다.
canary 우회
1. 무차별 대입 (brute force)
- x86 아키텍처에서는 4바이트의 카나리, x64 아키텍처에서는 8바이트의 카나리가 생성된다. 각각 카나리에는 NULL 바이트가 포함되있으므로, 실제로는 3바이트와 7바이트의 랜덤한 값이 생성된다.
- x86 경우에는 최대 256^3번의 연산을 해야하고, x64에서는 256^7번 연산을 해야한다. x64인 경우 연산량이 많아 현실적으로 알아내기 어려우며, 실제 서버를 대상으로 무차별 대입 시도를 계속할 수 있는 것도 불가능하다.
2. canary leak (TLS 접근)
- 프로그램 코드 안에서 스택 카나리를 leak 할 수 있다면, 이를 통해 우회할 수 있다.
해당 파일을 주석과 같이 컴파일 하고 메모리 보호기법이 어떤 것이 적용되어 있는지 checksec을 통해 확인한다.
코드를 확인해보면, 다음과 같은 정보를 알 수 있다.
- rbp와 buf 사이의 주소 거리를 알려준다. -> canary 주소 거리도 알 수 있음.
- buf에 입력을 총 2번 받는데, 두 곳 모두 버퍼 오버플로우가 발생한다.
첫번째 입력에서 0x100 크기만큼 입력을 받아 0x50 크기의 buf에 저장하고, printf 함수를 통해 이 buf를 출력해준다.
printf 함수는 0x00을 만날 때 까지 문자를 출력하기 때문에, canary의 8byte 중에서 앞 1byte는 0x00 값을 다른 값으로 채워주면 canary 값까지 출력시킬 수 있다. 이 것을 이용하여 canary의 값을 leak 할 수 있다.
두번째 입력에서는 exploit을 진행한다. 구한 canary 값을 그대로 넣어주고, 나머지는 버퍼 오버플로우의 RET 변조와 같다.
NX가 꺼져 있기 때문에, buf에 shellcode를 올리고 RET 값에 buf의 주소를 주면 exploit에 성공하게 된다.
pwntools을 통한 자세한 exploit 코드는 dreamhack.io에 접속하여 확인할 수 있다. 코드를 따라 이해하면서 직접 exploit 코드를 짜보고, 워게임 문제도 풀어보는 것을 추천한다.
reference
Mitigation: Stack Canary - https://dreamhack.io/lecture/courses/112