주요 내용으로 건너뛰기

메모리 취약점:과거, 현재, 미래 (3) Canaries

Canaries는 Classic buffer overflow 에 대한 방어책으로써 비교적 초창기에 등장한 대표적인 보호기법이다.

Canaries의 이름의 유래는 새(한국어 : 카나리아)로부터 유래했다. 왜 뜬금없이 새일까? 이는 canary in a coal mine에서 비롯된 것으로, 광부들이 광산에서 작업을 할 때 일산화탄소 등 독가스 중독으로 사망하는 사고가 자주 발생하자, 새장 안에 새를 넣고 같이 들고 다니면서 작업을 했다는 역사적 사실에서 기반한다. 사람은 중독을 느끼는데 시간이 오래 걸리지만 새는 비교적 빠른 시간 안에 사망하게 되고, 사람은 이를 보고 새가 죽으면 위험신호로 판단하고 서둘러서 탈출했다는 것이다.  (출처 : english-idiom-canary-coal-mine)


메모리 취약점 탐지, 특히 스택기반 버퍼 오버플로우에서 이러한 점에 착안하여 보호기법을 마련하였다. 가장 기본적인 아이디어는 Control-flow 관련 데이터를 보호하기 위해 예측하기 어려운 패턴의 값을 삽입하는 것이다.

함수 호출시에 진입 시점에 StackGuard가 스택에 있는 해당 함수의 복귀 주소 주변에 일명 Canary라고하는 예측하기 어려운 패턴의 값을 삽입한다.

함수가 종료되는 시점에, 해당 patter의 복사본과 비교해서 그 값이 변경되어 있는지를 점검한다.

만약 값이 불일치한다면 복귀 주소에 대한 버퍼 오버플로우 공격이 발생한 것으로 간주하고 해당 프로그램을 강제로 종료한다.


이 기법을 적용한 최초의 시스템은 StackGuard로 1997년 12월 발표된 후 1999년 1월에 출시되었다. StackGuard는 0x000aff0d 라는 값을 고정적인 Canary value 로 설정했는데, 이는 나름대로 고심한 결과이다. 왜냐하면 공격자가 0x000aff0d 라는 값을 알면서도 이를 강제로 삽입할 방법이 곤란하다는 것인데, 앞의 "00"은 널값으로 이를 strcpy 등을 통해 삽입할 수 없다는 것과, "0a", "0d"는 fgets에 대한 방어, "ff"는 EOF checks에 의해 필터링 되기 때문이다.

다만 StackGuard는 반환 주소에 대한 손상은 무조건 직접적인 버퍼 오버플로우를 통해서만 발생할 것이라고 가정했다. 때문에 간접적인 접근을 통해 카나리 값의 무결성은 보장하면서도 함수 복귀 주소만을 조작시킬 수 있는 또다른 공격기법이 출현하였다.

이에 1999년 발표된 Stack Shield는 이러한 문제를 해결하기 위해 반환주소 자체에 대한 무결성을 보존하고자 하였다. 함수에 진입할 때 복귀 주소를 별도의 주소공간에 분리하여 복사본을 만들어 놓는 방법을 통해, stack overflow를 해봤자 그 영역에 도달할 수 없도록 한 것이다. 함수가 종료될 때 기존에 안전하게 복사해두었던 반환 주소 값과, 실제 함수의 반환 주소를 비교하는 방식으로 점검한다. 무결성이 보장되지 못한 경우 오버플로우로 인해 스택의 복귀주소가 손상되었다고 판단하고 프로그램을 강제로 종료한다.


2000년대 초반이 되자, StackGuard와 StackShield를 우회하는 기법이 상당수 발표되었다. 

  • Bulba and Kil3r, “Bypassing StackGuard and StackShield,” Phrack Magazine, vol. 56, no. 5, Jan. 2000
  • G. Richarte, “Four different tricks to bypass StackShield and StackGuard protection,” June 2002

한편 Windows 에서도 이와 유사한 공격이 발생하였는데, David Litchfield 는 SEH(Structured Exception Handling)에 대한 Exploit을 통해 카나리 기반의 보호기법을 우회할 수 있음을 보였다. 

  • D. Litchfield, “Defeating the Stack Based Buffer Overflow Prevention Mechanism of Microsoft Windows 2003 Server,” in Blackhat Asia, Dec. 2003.

2006년 Matt Miller는 SEH exploitation으로부터 보호할 수 있도록 하는 기법을 “Preventing the Exploitation of SEH Overwrites”으로 발표하였는데, 이는 예외처리가 발생할 때 그 유효성을 검사할수 있도록 하였으며 실제로 취약점을 잘 탐지할 수 있으며 구버전 응용 프로그램과의 하위 호환성도 지원되어 Windows Server 2008과 Windows Vista SP1에 채택되었다. 이를 ASLR과 함께 적용한다면 SEH 에 대한 Exploit을 상당부분 저지할 수 있었다.


이처럼 Canary-based 보호기법은 초창기 제안에서 여러가지 부족한 점을 보완하였으며, 특히 StackGuard를 계승하고 단점을 보완한 SSP(Stack Smashing Protection)으로 알려진 일명 ProPolice 가 현재에도 널리 사용되고 있다. 

SSP를 적용하게 되면, 버퍼 오버플로우에 의한 포인터 훼손을 방지하기 위해 스택의 변수 배치가 재구성되게 된다. SSP는 실용적으로도 잘 구현되어, GNU C compiler 3.x에 적은 오버헤드로 성공적으로 구현되었고, 4.1부터 Main stream에 포함되었다. 이후 FreeBSD, OpenBSD, Ubuntu 등 주요 운영체제들이  스택 오버플로우에 대한 사실상의 표준 대응책으로 채택하게 되었다.

하지만 이러한 방어기법이 출시하자 공격 기법도 다른 방안을 마련하기 시작하였다. 사용자 데이터 영역과 프로그램의 영역의 제어 데이터를 뒤섞는 기법은 단지 스택에서만 발생하는 일이 아니기 때문에 Heap overflow(동적 메모리 할당 메타데이터 변조)과 포맷스트링 버그 등의 새로운 공격 기법이 등장하기 시작했다. (다음 글에서 계속...)

Software Security Engineer

CPUU 님의 창작활동을 응원하고 싶으세요?

댓글

SNS 계정으로 간편하게 로그인하고 댓글을 남겨주세요.