주요 내용으로 건너뛰기

메모리 취약점:과거, 현재, 미래 (1) 개요

메모리 취약점 및 그를 악용한 exploit 기법은 지난 25년간 꾸준히 가장 위험한 소프트웨어 버그의 상위 랭크를 차지하고 있다. 이것들을 막지 못하고 있는 이유는 도대체 무엇인가? 시스템을 기존보다 덜 취약하게 만들거나, 미래에 닥쳐올 위협들을 미리 예측하고 피할 수는 없는걸까?


본 포스트에서는 메모리 취약점의 과거와 현재 그리고 미래를 통합적으로 살펴볼 것이다. 기술적인 세부내용보다는, 우선 역사적인 관점에서 어떤 기술 트렌드들이 있었는지를 빠르게 훑어보고 싶은 독자들에게 도움이 되기를 바란다.

본 글을 시작으로, 앞으로 NX/DEP, Stack Canary, ROP, Heap overflow, Format String, ASLR, Null pointer dereference 등 대표적인 메모리 보호 기법과 그 공격방안에 대하여 하나씩 연재를 이어가고자 한다.

본 포스트의 내용은 아래의 내용을 참고로하여 재구성하였다.

  • H. Meer, “Memory Corruption Attacks The (almost) Complete History,” in Blackhat USA, July 2010.
  • Van der Veen, Victor, Lorenzo Cavallaro, and Herbert Bos. "Memory errors: the past, the present, and the future." International Workshop on Recent Advances in Intrusion Detection. Springer, Berlin, Heidelberg, 2012.
  • Szekeres, Laszlo, et al. "Sok: Eternal war in memory." 2013 IEEE Symposium on Security and Privacy. IEEE, 2013.
  • Fighting the War in Memory - Software Vulnerabilities and Defenses Today, 2014

개요

우선 C/C++ 언어로 작성된 프로그램에는 고전적인 소프트웨어 취약점이 내포되어 있다고 봐도 무방한데, 지금까지 알려진 취약점만해도 수두룩하다. CWE SNAS에서 공시하는 가장 위험한 소프트웨어 버그 25순위에서도 TOP 3순위를 차지하는 것이 바로 Memory errors이다. 

이를 막기 위한 다양한 countermeasures 방법론 역시 학계와 업계에서 폭넓게 제시되기는 했지만 여전히 문제는 현재 진행형이며, 그 countermeasures를 또다시 박살내버리는 새로운 공격기법 역시 계속해서 발표되고 있다. 

메모리 오류는 포인터 표현식을 사용하여 특정 Object에 접근하게 될 때 이것이 원래의 의도와 달라지는 경우 발생한다. 이러한 형태로는 크게 두가지로 구분할 수 있다.

  • Spatial error : 어떤 포인터가 그것의 참조 범위 바깥을 포인팅하는 상태에서 역참조 될 때 발생한다. 여기에는 초기화되지 않은 포인터, 또는 포인터가 아닌 데이터, 유효하지 않은 포인터 연산으로 인해 버퍼 오버플로우를 일으키는 등이 포함된다.
  • Temporal error : 프로그램이 어떤 포인터를 역참조하려할 때, 해당 포인터가 참조하던 object가 실제로 더이상 존재하지 않는 상태일 경우에 발생한다.이러한 문제들은 대표적으로 Dangling pointer 나 Double free 등의 상황에서 기인하게 된다. 



MemSafe: ensuring the spatial and temporal memory safety ofC at runtime

메모리 오류로 인해 발생할 수 있는 대표적인 취약점과, 그를 Exploit하는 방법, 그리고 그 방어기법들이 지금까지 많이 연구되고 있는데 본 글을 통해 타임라인을 톺아보고자 한다.


메모리 오류에 대해서는 1972년 Computer Security Technology Planning Study Panel 라는 산학민관 협의체에서 공식적으로 공론화된 것으로 본다. 하지만 실제적으로 그러한 위협이 발생한 것은 1988년 11월 2일의 인터넷 웜(일명 Morris Worm) 사태이다. 

당시 코넬 대학교에서 대학원 생활을 하던 Robert T. Morris는 MIT를 대상으로 취약한 시스템에 대한 공격을 수행하는 악성 프로그램을 만들었고 이것이 빠르게 확산되면서 결국에는 대부분의 전산망을 불거상태로 만들고 말았다. 그는 이 일로 컴퓨터 사기 및 남용 방지법(Computer Fraud and Abuse Act) 위반으로 인해 기소된 최초의 사람이 된다. 결국 그는 1990년 12월 재판결과 징역 3년의 집행유예, 400시간의 사회 봉사, 10,050 달러의 벌금을 선고받았다. 그는 보안 결점을 보여줌으로써 현재 컴퓨터 및 네트워크 시스템이 얼마나 안전하지 못한지를 보여주기 위한 행동이었다고 항소하였으나 기각되었고 결국 1994년 만기로 형을 마치게 되었다.

이 사건 이후 사이버테러에 대한 경각심이 고취되고, 이를 대응하기 위한 CERT/CC(Computer Emergency Response Team Coordination Center) 기관이 최초로 설립되기도 하였다. 컴퓨터 보안에 대한 관심이 점차 생겨나기 시작한 것이다. 윈스콘신 대학의 Barton P Miller 교수 등은 1990년 fuzzing 방법을 통해 현존하는 Unix system이 얼마나 보안적으로 취약한지를 입증하는 연구를 수행하기도 하였다.

1993년 Scott Chasin이라는 사람이 보안 취약점에 대한 폭넓은 정보 공유를 위해 Bugtraq이라는 메일링 리스트를 운영하기 시작하였다. 당시 사람들은 CERT/CC가 제대로된 일처리를 하지 못한다고 불만이 많은 상황이었기에 Bugtraq이 각광받기 시작하였다. 실제로 CERT/CC에 의뢰를 하게 되면 그 결과를 받는데까지 엄청난 시간이 소요되어 하염없이 기다릴 수밖에 없었는데, 그에 반해 Bugtraq를 통해 공지되는 내용들은 폭넓은 취약점 연구와 그 대응 방안에 대한 자유로운 토론이 진행되곤 하였다. 이를 통해 다수의 사람들이 취약한 시스템을 빠르게 패치할 수 있었다. 

1995년 Thomas Lopatic은 NCSA HTTP daemon 프로그램이 갖는 취약점을 단계적으로 설명하며 메모리 오류에 대한 심층적인 결과를 보여주었다. 이후 Peiter Zatko(일명 Mudge)는 흔히 Stack based buffer overflow 로 알려져있는 고전적인 메모리 취약점 기법을 구체적으로 어떻게 수행할 수 있는지에 대한 노하우를 공개하였다. [P. Zatko, “How to write Buffer Overflows,” 1995.]

이때까지는 아직 메모리 오류에 대한 완화기법(Countermeasure)에 대해 별다른 논의가 되지 않았는데, Mudge의 노하우가 공개된 이후 이에 영향을 받은 Elias Levy가 메모리 오류에 대한 보호 메커니즘에 대해서 논의를 전개하였고 이것이 바로 지금까지도 널리 알려져 있는 “Smashing The Stack For Fun And Profit,”이다. 1996년 Phrack Magazine에 Aleph one 이라는 필명으로 기고되어 있다.


이후 보안 업계에서는 메모리 취약점을 보호할 수 있는 기법들이 활발하게 연구되어왔고, 누군가는 또다시 그 보호기법을 무력화시킬 수 있는 공격기법을 만들어내었다. 그러한 싸움은 25년간 현재까지도 지속되고 있는 실정이다. 본 글을 시작으로 하여 앞으로 시리즈 형태로 몇개의 중요 메모리 취약점과 그 보호기법 등의 현황을 소개하고자 한다.

먼저 Non-executable(NX) stack 방법이 도입되었다. 이는 스택 기반 버퍼 오버플로우 공격에 대 한 첫번째 방어책으로  Alexander Peslyak(a.k.a. Solar Designer )에 의해 제시되었으며, StackPatch[Linux kernel patch to remove stack exec permission]라는 기술로써 그 구현체가 1997년 리눅스 시스템에 적용되었다. 다음 두번째 글에서 NX 보호기법 및 ROP 에 대해 다룰 것이다.


1998년 1월, USENIX Security Symposium 에서 Crispan Cowan 등의 연구진이 [StackGuard: Automatic Adaptive Detection and Prevention of Buffer-Overflow Attacks] 논문을 발표하였다. 이것이 일명 Canary로 알려진 기법으로, 스택 변수와 함수의 return address 사이에 특정한 패턴을 확인용으로 삽입하여, 만약 이 내용이 임의로 수정될 경우 스택 오버플로우 공격이 발생한 것으로 간주하는 기법을 발표하였다. 이러한 canary-based defense에 대해서 세번째 글에서 다루려고 한다.


다양한 스택 기반 공격의 보호기법이 발표됨에 따라, 해킹기법을 연구하는 사람들은 메모리 내에서 스택이 아닌 다른 영역에 관심을 돌리기 시작했고 그 대상은 Heap공간이었다. 1999년 Matt Conover와 w00w00 보안 그룹은 Heap 기반의 overflow를 다루는 내용[w00w00 on Heap Over- flow]을 공개하였다. 이러한 힙기반 공격에 대해서 네번째 글에서 다루겠다.


1999년 9월, Tymm Twillman이 Format String Attack이라는 기법을 공개하였다. 그가 Bugtraq에 공유한 내용에 따르면 ProFTPD 프로그램에 대하여 Exploit 한 과정을 보여주고 있다. 포맷 스트링 공격은 이후에도 굉장히 중요한 공격 방법으로 유지되고 있으며 이 부분을 다섯번째 글에서 다루겠다.


앞서 StackGuard와 같이 스택 영역에 임의의 값을 넣는 것을 한단계 더 발전시켜서, 아예 Stack의 주소를 혼잡화시켜버리는 아이디어가 2001년 PaX Team에 의해 제시되었다. 이는 일명 ASLR(Address Space Layout Randomization)으로, 스택이 위치한 주소가 무작위로 배치되기 때문에 공격자가 그 위치를 정확히 알지 못하도록 하는 것이다. 처음에는 스택의 위치만을 대상으로 적용되었다가 점차 현재는 커널 영역에까지 ASLR이 적용되고 있다. ASLR 과 그에 대한 공격 기법에 대해 6번째 글에서 다루려고 한다.


그 외에도 Null pointer dereference 기법이 2001년 공개되었다. 이는 CVE-2001-1342라는 취약점을 통해 세상에 알려졌다. 대부분의 사람들은 이러한 공격은 그저 단순한 서비스 마비 정도만을 일으킬 뿐 별로 큰 문제는 아니라고 치부하였다. 그러나 2008년 Mark Dowd에 의해 Null Pointer Dereference를 이용하여 임의의 코드를 삽입하는 [Application-Specific Attacks: Leveraging the ActionScript Virtual Machine, 2008] 형태의 공격도 얼마든지 가능하다는 것이 입증되었다. 이 기법에 대해 7번째 글에서 다루고 본 시리즈를 마무리하고자 한다.




Software Security Engineer

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

댓글

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