프로그래밍 언어의 측면에서 memory safety란 무엇인가에 대해 알아보자.

 

[0]

익히 알려진 버퍼 오버플로우(buffer overflow)dangling pointer 취약점 등의 공통점은 무엇일까? 바로 이들이 완벽하지 않은 memory safety를 노린 공격이란 것이다. 논문 SOK : Eternal War in Memory에서는 memory safety한 언어를 다음과 같은 공격/에러 발생이 불가능한 언어로 정의하고 있다. 

1. buffer overflow
2. null pointer dereference
3. use after free
4. use of uninitialized memory
5. illegal free (of an already-freed pointer, or a non-malloced pointer)

이 포스팅에서는 위 5가지 공격 혹은 에러를 아래에서 하나씩 살펴보자.

 

[1] Buffer Overflow

가장 유명한 공격 중 하나이다. 다음의 예제 코드를 보자. 

void func(char buf[]){
	scanf("%s",buf);
	return;
}

int main(void){
	char str[15];
	func(str);
}

예제 코드의 func()에서, 버퍼 사이즈 체크를 하지 않는 scanf함수를 사용하여 buf를 채우고 있다. 이 상황에서 null포함 15바이트 이상의 입력이 들어오게 되면 buf사이즈를 넘쳐 흐르게(=overflow)되고 이로 인해 스택 프레임의 지역 변수, return address 등의 데이터들이 덮어 쓰인다. 이 중 return address를 공격자가 원하는 지점으로 덮어 씌우게 되면 함수 리턴시에 실행 흐름(control-flow)을 제어할 수 있게 된다. 꼭 return address가 오염되지 않더라도, 지역 변수가 보안상 민감한 정보가 덮어쓰워지면(ex. 함수 포인터) 이 또한 큰 문제가 된다.

 

위의 예제 코드에서는 스택 메모리 영역에 대해 오버플로우가 발생하였다. 스택 영역은 힙 영역에 비해 할당/해제의 흐름이 단순하므로, 방어 기법도 비교적 단순하다. 대표적으로, 스택 canary를 이용한 방어 기법이 있다. 반면에, 힙 영역에 대한 overflow 공격은 조금 더 복잡하며, 방어 기법도 더 어렵다. 이에 대해서는 별도의 포스팅으로 다루도록 하겠다.

 

[2] Null Pointer Dereference

단순하다. Null값을 갖는 포인터를 역참조 할 때 발생하는 에러이다. C에서 null pointer dereference는 undefined behavior이며, java에서는 NullPointerException이 발생한다. 

 

[3] Use After Free(UAF)

free된 메모리 영역은 더 이상 접근이 불가능해야 하지만, 메모리 할당자의 특성을 이용하여 접근을 시도하는 공격이다.

ptr1 = malloc(10);
free(ptr1);
ptr2 = malloc(10);

malloc()은 메모리 해제 시에 더 빠른 퍼포먼스와 메모리 관리를 위해 사이즈별로 캐싱을 지원한다. 즉, ptr1에서 free된 영역이 그대로 사이즈가 같은 ptr2에서 다시 할당된다! free에서는 메모리 공간을 초기화하지 않기 때문에(퍼포먼스 오버헤드가 너무 크다), ptr1에서 사용했던 메모리 영역에 남아있는 데이터를 그대로 사용할 수 있다! 즉 이 공간에 민감한 정보가 있으면 그대로 유출이 가능하다.

 

위와 같은 예제 코드는 메모리 할당자(malloc과 같은 함수)의 구현 방식에 따라서 얼마든지 방어할 수 있다. 하지만 새로운 메모리 할당자의 구현이 등장하게 되면, 공격자 또한 이 코드를 볼 수 있기때문에 새로운 취약점을 찾아낼 수 있다. 그래서 메모리 할당자의 구현 방식만으로  UAF 공격을 완전히 막는 것은 어렵고, c++의 스마트 포인터와 같은 해법이 제시되곤 한다. 상세한 방어 기법을 여기서 다루진 않는다.

 

[4] Use of Uninitailized Memory

일반적으로 에러로 취급되지만, 명시적으로 에러를 뱉지 않는 경우가 많기 때문에, 디버깅하기 극도로 힘들다. 

 

[5] Illegal Free

null pointer에 대해 free를 시도하거나, 스택 메모리 영역에 대해 free를 시도하는 등을 가리킨다. 가장 재미있는 사례는 double free이다. double free는 말 그대로 이미 free된 메모리 영역에 대해 다시 한번 free를 시도하는 것을 의미한다. 단순하게 생각하면, 해제된 공간을 다시 해제하는 절차는 딱히 문제가 될 부분이 없어 보인다. 하지만 이는 memory manager의 상태를 오염시킬 수 있기 때문에 에러를 이르킬 수 있다. 이 과정은 상당히 복잡하다. 이 링크나, 이 링크 등을 참조하자. double-free에 대해서는 나중에 상세히 포스팅 할 예정이다.

 

[6]

이상에서 memory safety의 취약점을 노린 5가지 대표적인 공격/에러를 보았다. 다음 포스팅에서는 이것들을 어떻게 방어할 수 있을지를 알아본다.

 

 

참고

[1] http://www.pl-enthusiast.net/2014/07/21/memory-safety/

 

What is memory safety? - The PL Enthusiast

Memory safety is a commonly used term - but what is its definition (and why does that matter)?

www.pl-enthusiast.net

 

'Computer Science > Security' 카테고리의 다른 글

Confidential Computing이란  (0) 2020.03.24
double-free 취약점  (0) 2020.02.04
Memory safety - 3  (0) 2019.12.02
Memory Safety - 2  (0) 2019.11.12

+ Recent posts