[linux] 2. Canary에 대하여
두비니
·2020. 10. 13. 05:20
Canary
Linux Memory Protection - 2
1. What is Canary?
**Stack Smashing Detected** 빼앵앵애ㅐㅇ애에에ㅔㅔㄱ
Canary기법이란 'buffer와 SFP(Stack Frame Pointer) 사이에 buffer overflow를 탐지하기 위한 임의의 데이터를 삽입하는 기법'입니다. 왜 이런 걸 넣냐구요? 기본적인 스택 구조와 카나리가 활성화된 스택 구조의 차이점을 봅시다.
왼쪽은 Canary가 꺼져있고, 오른쪽은 Canary가 활성화된 스택입니다. buffer와 SFP사이에 Canary라는 것이 생겼죠?
많은 공격기법은 eip 레지스터를 변경하는 것을 목표로 두고 있는데, 그 중 다수의 기법들이 RET를 변경합니다. 그러나 Canary로 Memory Corruption을 막는다면 buffer overflow 등을 통해 sfp/ret에 접근하려 하면 canary가 변경되어 경고가 발생합니다.
Canary에는 다음과 같은 종류들이 있습니다.
1) Terminator Canary
문자열 끝문자를 이용하여 canary를 구성하는 방법으로, canary값으로 NULL, CR, LF, 0xff 값들의 조합이 사용됩니다. 공격자는 공격코드상에 다음과 같은 값을 삽입할 수 없기 때문에 canary값에 접근이 불가능합니다.
+) 참고 : NULL값으로만 이루어진 canary는 NULL canary라고 부릅니다.
2) Random Canary
프로그램을 실행할 때마다 임의의 canary 값을 사용합니다. 그렇기 때문에 공격자는 Canary값을 예측할 수 없으므로 공격에 어려움이 발생합니다.
3) Random XOR Canaries
Canary의 값을 모든 제어 데이터 또는 일부를 사용해 XOR-Scramble을 통해 생성합니다.
2. Training
오늘도 어김없이 아주 간단한 코드를 작성해봅시다.
#include <stdio.h>
#include <stdlib.h>
/*
*CANARY OFF*
gcc -m32 -mpreferred-stack-boundary=2 -fno-stack-protector canary.c -o canary
*CANARY ON*
gcc -m32 -mpreferred-stack-boundary=2 canary.c -o canaryON
*/
int main()
{
char buf[256];
gets(buf);
printf("addr : %p\n", buf);
return 0;
}
전형적인 BOF를 위한 코드이죠? 컴파일 할 때 카나리 여부에 따라 컴파일 옵션을 다르게 해주어야 하는데, 각 옵션은 다음과 같은 뜻을 가지고 있습니다.
- -m32 : 32비트로 컴파일
- -mpreferred-stack-boundary=2 : 스택 간 더미 없애는 옵션
- -fno-stack-protector : canary를 끄는 옵션
옵션들은 철저하게 카나리를 보기 위한 옵션들만 켜놨습니다. 참고하시길
이제 어셈블리어 코드를 봅시다.
어셈 코드들을 보면 확실히 canary가 있는 쪽이 코드가 더 길어진 것을 확인할 수 있습니다.
일단 canary가 존재하면 gs:0x14에서 Canary값을 가져와 저장하고, 이후에 이 값을 ebp-0x4에 저장합니다.
그리고 에필로그 실행 전 스택에 저장했던 Canary값과 gs:0x14의 원본 값을 비교하여 값이 다르다면 공격을 당했다고 판단하고, 프로그램을 종료시키는 __stack_chk_fail함수를 call합니다.
+) 추후에 카나리 직접 확인하는 것도 추가하도록 하겠습니다. 방법만 서술하자면, main+15에서 ebp-0x4에 카나리를 저장하기 때문에 main+18에서 브레이크포인트를 걸어두고 ebp-0x4의 값을 확인해주면 됩니다.
그럼 두 프로그램간의 차이점을 봅시다.
일단 페이로드는 A*256+B*4입니다. canary가 없는 프로그램의 경우(아래) SFP가 0x42424242라는 주소로 가려고 해서 Segmentation fault가 발생합니다. 이건 단순히 제가 프로그램에 존재하지 않는 주소를 넣어줬기 때문에 프로그램이 터진 것 뿐입니다.
하지만 canary가 있는 경우에는 Segmentation Fault가 아니라, *** stack smashing detected ***가 발생합니다. 그 이유는 buf 밑에있는 canary부분이 기존의 canary와 일치하지 않기 때문에 다음과 같은 에러와 함께 종료하는 것입니다.
두 프로그램의 차이점을 알았음 좋겠네염
system("/bin/sh")를 해주는 함수를 만들어 놓은 뒤, 그냥 canary파일은 익스되게 하면 더 좋을 것 같은데 귀찮습니다. 죄송...,,,..
3. Exploit Technique?
결국 CTF문제들에서 Canary를 다루게 된다면 Random Canary를 가장 많이 만나게 될 것입니다. 그래서 보통 canary값을 구하는 Canary Leak방법을 가장 많이 이용합니다. 이 Canary Leak는 단독으로 문제로 나오진 않고, 다른 기법이 메인이고 그걸 시행하기 위해 Canary Leak을 사용합니다. Canary Leak을 하는 방법은 이 Canary가 저장된 Stack Address를 알거나 스택의 값을 읽어올 수 있는 프로그램이 있다면 Canary의 값을 확인할 수 있다.
본 글은 이론적인 부분을 설명하는 글이기 때문에, 실전 적용한 글들의 링크만 걸어두도록 하겠습니다.
Codegate 2014 angry_doraemon : nextline.tistory.com/103
Codegate CTF_2017 BabyPwn : holinder4s.tistory.com/tag/canary%20leak
나머지 글들
0. Abstract : dokhakdubini.tistory.com/297
1. ASLR : dokhakdubini.tistory.com/298
2. Canary <--- You are here
3. NX(with DEP) : dokhakdubini.tistory.com/300
4. PIE : dokhakdubini.tistory.com/304
5. ASCII ARMOR
'Coding_Algorithm > Operating System' 카테고리의 다른 글
[linux] 4. PIE에 대하여 (0) | 2020.11.27 |
---|---|
[linux] 3. NX(with DEP)에 대하여 (0) | 2020.10.13 |
[linux] 1. ASLR(Adress Space Layout Randomization)에 대하여 (0) | 2020.10.11 |
[linux] 0. 메모리 보호기법 - abstract (0) | 2020.10.11 |
bits.c code (비공개) (0) | 2020.10.07 |