Linux Kernel(4.14) Hacks

rousalome.egloos.com

포토로그 Kernel Crash




[SW][에세이] 해킹: Heap(힙) Protection으로 해커 공격 원천 봉쇄 임베디드 에세이

스택 오버플로우
혹시 스택 오버플로우란 용어를 들어본 적이 있나요?
소프트웨어에서 스택 오버플로우란 지역 변수를 너무 크게 잡아 프로세스가 쓰고 있는 스택 메모리를 깨는 것을 의미합니다. 그런데 해커들은 스택 오버플로우를 써서 해킹을 합니다.

말 그대로 함수 인자 값 및 각종 local/auto 변수들이 있는 스택에 **일부러** 정해진 크기 보다 더 많은 데이터를 써서 컴퓨터를 해킹하는 것입니다. 여기서 해킹이라는 용어의 의미는:
  1> 해커가 실행하고자하는 악성 코드를 실행할 수 있도록 컴퓨터의 제어권을 탈취하거나
  2> 제어권의 탈취가 아니더라도 프로그램에서 매우 중요한 데이터를 조작하는 것

을 뜻합니다. 

하지만 해커가 2 번째 방식으로 중요한 데이터를 획득하는 것은 어렵습니다. 그 이유는
대부분이 콜스택에 있는 return address를 다른 주소로 바꾸어 해커가 원하는 악성 코드가 실행하는 방식을 쓰기 때문입니다.

해커가 스택 오버플로우로 원하는 코드를 실행하는 방식은 이미 많이 연구가 됐고 많은 방어 패치 코드가 반영돼 있습니다. 그러니 스택 오버플로우로 취약점을 악용하기는 어렵습니다.

그런데 해커들이 스택 오버플로우에서 눈을 돌려 힙을 연구하기 시작했습니다.

힙(Heap) 오버플로우(Overflow)
힙 오버플로우 개념은 간단합니다.

만약 malloc으로 20바이트의 메모리를 할당 받았다고 가정합니다.
이 때 20 바이트보다 많은 데이터를 쓸 경우 어떤 특정한 패턴을 볼 수 있습니다.

이 점을 노린 것이 힙 오버플로우 해킹입니다.

이것을 이해하기 위해서 힙을 할당하고 해제하는 malloc()와 free() 함수가 어떻게 메모리를 할당하고 해제하는지 이해 해야만 한다. malloc()함수와 free() 함수로 대표되는 힙 함수군은 작은 크기의 메모리를 빠르게 할당 해주는 것이 그 첫 번째 임무입니다. 

대표적인 구현 방법으로는 GNU libc에서 사용 중인 Doug Lea의 malloc 구현을 예로 들 수 있습니다. 

먼저, 간단하게 생각보겠습니다. malloc() 함수을 호출하면 미리 할당한 큰 메모리 블럭(Unix에서는 sbrk로, Windows에서는 VirtualAlloc으로)에서 작은 메모리 공간을 때어내서 돌려주고 그 정보를 기록하는 방식입니다. 이 정보는 링크드 리스트나 기타 자료구조로 저장할 것입니다. (따라서, malloc 소스는 완벽하게 user-level에서 돌아가는 알고리즘입니다. 그래서 해킹이 용이한 것입니다.)

실제 malloc에서 사용하는 방법은 데이터를 다음과 같이 저장합니다.
+-----------------------------------------------------+-----
| Data  | meta-data | Data  | meta-data | Free space  | ...
+-----------------------------------------------------+-----

즉, 실제로 사용자가 쓰는 data 영역 사이에 할당한 메모리들을 관리하기 위한 meta-data가 존재합니다. 이 meta-data는 할당한 크기, 앞에 있는 블럭이 사용 여부, 해제된 메모리의 경우에는 prev/next 프리 노드들에 대한 데이터 등등과 같은 정보를 저장합니다. 이러한 알고리즘은 이미 십여년간 사용되고 있습니다.

malloc()와 free() 함수 호출 횟수는 상황에 따라 매우 커질 수 있습니다. 
크롬 브라우저에서 페이지를 몇번만 열고 닫아도 수백만번이 호출됩니다. 구글 피카사의 경우에는 수천만번이 호출됩니다. 그 만큼 malloc()와 free() 함수는 컴퓨터 프로그램의 핵심 중에 핵심이라 할 수 있습니다. 그래서 그 속도와 메모리 관리가 중요하고 지금까지는 속도 및 적은 메모리 낭비를 위해 위와 같은 방법을 이용하는 것입니다.

그러나 모든 이를 서로 믿을 수 있었던 시절에는 모두가 행복하였으나, 더 이상 세상은 그렇게 평온하지가 못합니다. 수 많은 해커/크래커들이 이런 점을 악용해서 마구 나쁜 짓을 하는 것입니다.

그 방법은 간단합니다. 주어진 크기보다 데이터를 넘치게 써서 meta-data를 조작하는 것입니다. 그래서 이른바 forward consolidation와 backward consolidation이라는 방법을 이용하여 제어권을 탈취하는 것입니다! 간단하게 개요를 설명하자면 meta-data에는 prev/next free node에 대한 정보가 있는데 이것을 조작하는 것입니다. 그런 뒤 뒤의 노드가 free가 될 때 무언가 잘못된 일이 벌어지게 되고 재앙이 닥치는 것입니다. 

대표적인 예로 Code Red Worm이 이러한 heap overflow를 악용한 것입니다.

이런 예는 수도 없이 많습니다. 여러분의 윈도우가 귀찮게 보안 업데이트를 해야한다고 알리면 바로 이러한 문제를 고치기 위해서라는 것으로 이해하면 될 것입니다.

그런데 왜 이런 문제가 일어나는지 생각해봅시다. 
그것은 지금까지 수 많은 프로그래머들이 이러한 공격을 감안하지 않고 프로그램을 짜왔기 때문입니다. 대표적인 경우로 strcpy를 보면, 이 함수는 char* 형태의 인자 두개를 받습니다. 그러나 이 char*의 길이를 체크하지 않기 때문에 악의적인 스트링 값을 준다면 주어진 공간보다 더 많이 써서 overflow가 일어날 수 있는 것입니다. 

실제로 2002년 리눅스 아파치 웹서버에서 일어난 Linux/Slapper worm 공격은 OpenSSL 패키지의 취약성을 노린 것입니다. 클라이언트 키를 받아서 저장하는 버퍼가 8바이트인데 해커가 이 보다 더 많은 데이터를 악의적으로 보내어 내부 자료구조를 고쳐 쉘 코드를 수행하게끔 악용하는 것입니다.

힙(Heap) Protection
그렇다면 어떻게 하면 heap overflow 공격을 막을 수 있을까요? 여러가지 방법들이 제안됐으나 그 중 핵심은 data 사이에 있는 meta-data를 아예 다른 프로세스로 옮겨버리는 것입니다. 그러면 더 이상 해커가 공격할 수 있는 meta-data가 없으니 원천적인 공격 봉쇄가 되는 것입니다. 이 아이디어는 상당히 간단한 것이었고 너무나 당연한 것인데 왜 아무도 이런 생각을 하지 못하였을까하고 느낄 정도였습니다.

참고 문헌:
[1] http://doc.bughunter.net/buffer-overflow/free.html
[2] http://securityresponse.symantec.com/avcenter/reference/analysis.slapper.worm.pdf

덧글

댓글 입력 영역