스택 카나리는 함수의 프롤로그에서 스택 버퍼와 반환주소 사이에 임의의 값을 삽입하여 함수의 에필로그에서 해당 값의 변조를 확인하는 보호 기법이다. 만약 카나리값의 변조가 확인되면 프로세스는 강제로 종료된다.
카나리 보호기법을 확인하기 위한 코드는 다음과 같다.
#include <stdio.h>
int main()
{
char buf[8];
read(0, buf, 32);
return 0;
}
컴파일 할때 기본적으로 카나리 보호기법이 적용되며, -fno-stack-protector 옵션을 적용해야 카나리 없이 컴파일을 할 수 있다.
카나리 보호기법이 적용된 바이너리와 적용되지 않은 바이너리에 긴 입력값을 주었을 때의 결과는 다음과 같다.
gdb로 main 함수를 비교하면 다음과 같다.
오른쪽이 카나리 보호기법을 적용한 바이너리의 main 함수이다.
프롤로그 부분에서 다음의 코드가 추가되었고,
0x000000000040059e <+8>: mov rax,QWORD PTR fs:0x28
0x00000000004005a7 <+17>: mov QWORD PTR [rbp-0x8],rax
0x00000000004005ab <+21>: xor eax,eax
에필로그 부분에서 다음의 코드가 추가되었다.
0x00000000004005cd <+55>: mov rcx,QWORD PTR [rbp-0x8]
0x00000000004005d1 <+59>: xor rcx,QWORD PTR fs:0x28
0x00000000004005da <+68>: je 0x4005e1 <main+75>
0x00000000004005dc <+70>: call 0x400460 <__stack_chk_fail@plt>
추가된 프롤로그(main+8)에 bp를 걸고 실행한 후 코드를 한 줄 실행하면 rax에 첫바이트가 널바이트인 8바이트 데이터가 적용되어 있는 것을 확인할 수 있다.
생성된 8바이트 데이터는 main+17줄의 코드에서 rbp-0x8의 위치에 저장된다.
이후 main+55에 bp를 걸고 실행하여 정상적인 입력값을 주게 되면 에필로그 부분에서 rbp-0x8에 저장된 카나리 값을 rcx로 옮기고 fs:0x28에 저장된 카나리와 xor 연산을 한다. 두 값이 동일하면 0이 나오므로 main+75로 점프하면서 프로그램이 정상 종료된다.
만약 긴 입력값이 들어가 카나리 값이 있는 rbp-0x8의 데이터가 변조되면 xor 연산에서 0이 아닌값이 나오므로 main+68의 __stack_chk_fail함수를 실행하며 프로세스가 강제로 종료된다.
'Security & Hacking > Technical & etc.' 카테고리의 다른 글
[Pwnable] Frame faking(Fake EBP)_Lazenka (0) | 2021.05.24 |
---|---|
[Pwnable] PIE 보호기법 (0) | 2021.05.13 |
[Pwnable] ASLR 보호기법 (0) | 2021.05.08 |
[Pwnable] RTL(Retrun To Libc) x64_ Lazenca (0) | 2021.04.26 |
[Pwnable] RTL(Retrun To Libc) x86 _ Lazenca (0) | 2021.04.23 |