주요 내용으로 건너뛰기

메모리 취약점:과거, 현재, 미래 (2) NX / DEP

memory error 를 이용한 취약점 중 가장 널리 알려져있는 것은 아마 Stack-based buffer overflow일 것이다. 누구나 한번쯤은 들어보았고 충분히 이해할만한 단순한 개념을 기반으로하지만 이 취약점은 현재까지도 여전히 유효하다. 

Stack-based buffer overflow는 말 그대로 스택 버퍼에 저장될 내용이 그 공간의 한계를 초과하여 주변부의 메모리 영역까지 덮어쓸 때 발생하는 오류이다. 이를 악용하여 버퍼의 끝 부분을 너머 함수의 return address가 저장된 공간에 닿을 때까지 내용을 덮어버리면, 해당 함수가 종료되고 return될 때 임의의 코드를 수행할 수 있게 되는 문제가 발생한다.

이러한 취약점을 막기 위해 등장한 개념이 Non-executable stack이다. 말 그대로 스택의 내용이 실행될 수 없게 하는 것인데, 스택의 특정 부분의 속성값을 설정함으로써 이 byte가 마킹되어 있다면 이 스택의 내용은 실행할 수 없는 것으로 간주하며 만약 이를 위반하는 시도가 발생한다면 프로그램에서 crash가 발생하여 강제로 종료된다. 


이런 아이디어의 시초는 Alexander Peslyak(필명 : Solar Designer)에 의해 1997년 리눅스 커널 부분에 일부 적용되면서부터이다. 

  • S. Designer, “Linux kernel patch to remove stack exec permission,” April 1997.
  • S. Designer, “Non-executable stack patch,” June 1997.

그러나 이러한 패치가 적용된지 불과 몇달도 채 지나지 않아, Solar Designer는 스스로 해당 시스템의 보호기법을 우회할 수 있는 새로운 공격기법을 발견하게 된다. 스택상에 저장된 코드로 return하는 것이 아니라, 라이브러리의 함수 주소와 인수로 만들어진 호출을 가짜로 조작하여 스택에 넣는 것이다. 취약하게 구현된 함수에서 return되면 라이브러리 함수를 실행하는 것으로 전환되는 효과가 있다. Dynamically linked & loaded 된 라이브러리라면 무엇이든 이러한 공격의 재료로 사용될 수 있는데, 그 중에서 특히 system("/bin/sh")와 같은 C언어 라이브러리 함수들이 자주 이용됨에 따라 이러한 공격의 별칭은 return-into-libc 로 붙여졌다.

Solar Designer는 non-executable을 적용한 stack patch가 return-into-libc에 견딜 수 있도록 다시 업그레이드를 선보였다. [“Getting around non-executable stack (and fix),” August 1997.]

하지만 이후 1999년 J. McDonald는 Unix 기반 시스템의 mprotect system call (windows 의 경우 VirtualProtect API)를 사용하여 기존 non-excutable로 설정되어 있지 않은 데이터 영역의 값을 이용하여 임의 코드를 삽입 후 실행하는 공격기법을 보였다. [“Defeating Solaris/SPARC Non-Executable Stack Protection),”] 이 기술은 non-executable 데이터 보호기법을 우회하는 일반적인 기술로 널리 사용되고 있다.

2000년, PaX team은 “Design & Implementation of PAGEEXEC”이라는 제안을 통해 새로운 non-executable stack 보호기법을 발표했다. data segment에 삽입된 코드가 실행되는 것을 방지하고, return-into-libc 를 수행하기 어렵도록 다양한 대비책을 마련하였다. PaX를 적용하면 data page에 기록은 할 수 있지만 실행할 수는 없으며, 만약 실행가능한 속성을 적용하게 되면 반대로 더이상 기록할 수 없게 만들었다. 현재의 대부분의 프로세서들은 하드웨어 기반의 NX(non-executable) bit를 지원하고 있는데 PaX가 이를 이용하게 된다. 만약 하드웨어적인 지원이 안되는 경우 소프트웨어적으로 처리할 수 있도록 하였다. 또한 PaX에는 mmap을 난독화하여 프로세스의 스택과 라이브러리가 로드되는 위치를 찾을 수 없도록 하기도 하였는데, 이는 추후 설명할 ASLR(Address Space Layout Randomization)의 시초가 된다.

하지만 곧 이를 비웃기라도하듯, 2001년 Rafal Wojtczuk(필명 Nergal)이라는 사람에 의해 또다시 무력화되고 말았다. 이 방법은 ELF 바이너리의 동작원리를 분석하여 PLT(Procedure Linkage Table)을 조작함으로써 Return-into-libc를 성공시킨 것이다. 이를 통해 mmap 기반의 randomization 역시 취약성이 있다는 것이 확인되었다.

2003년, OpenBSD 3.3 버전이 출시되었는데 여기에 buffer overflow 를 방지할 수 있는 다양한 기법들이 대거 포함되었다. 

  1. 사용자가 PROT_READ 로 페이지를 요청할 때 묵시적으로 처리하지 않고 독립적으로 처리할 수 있도록 PROT_EXEC를 적용하였으며 pmap module을 개선하였다.
  2. 일명 W^X : 메모리에 쓰기 및 실행가능 동작은 서로 Exclusive Or 하여, 동시에 수행될 수 없도록 함
  3. .rodata segment에 접근하기 위해서는 PROT_READ 권한만 부여되어야 함.(예전에는 PROT_READ | PROT_EXEC 였음) 이를 분리함으로써 .rodata 세그먼트가 읽기 전용이어서 공격자가 특정 명령어를 찾아내더라도 실행할 수는 없도록 하였다.
  4. Canary-based protection의 일종인 ProPolice을 적용하였다.

이 시점 이후부터 유명 운영체제 제조사들은 Buffer Overflow 대응책을 본격적으로 채택하기 시작하였다. Red Hat은 Enterprise Linux Version 3부터 다양한 보안 패치를 제공하였다. (“New Security Enhancements in Red Hat Enterprise Linux v.3, update 3,” August 2004.) 특히 kernel 기반의 보안 솔루션이 적용되었는데 일명 ExecShideld이 대표적이다. 이는 PaX와 유사한데, Stack 뿐만 아니라 가상 메모리의 주소 공간을 대폭적으로 non-executable로 설정하였다. 또한 stack, shared library, program heap 및 텍스트 영역 등의 위치를 전부 randomize 하였다. (PIE, position independent executables). 또한 흔히 SSP(Stack Smashing Protector)로 알려져 있는 Canary-based protection인 ProPolice도 도입하였다.

마이크로소프트의 Windows XP Service Pack 2에도 2005년부터 DEP(Data Execution Protection)기술이 적용되었다. 이는 결국 프로그램의 메모리 영역에 있는 코드를 실행할 수 없도록 하는 것이다.(Microsoft, “A detailed description of the Data Execution Prevention (DEP) feature in Windows XP Service Pack 2, Windows XP Tablet PC Edition 2005, and Windows Server 2003,” September 2006.) PaX와 유사하게 DEP 역시 하드웨어 기반과 소프트웨어 기반의 DEP 모두 가능하다.

이처럼 다양한 Non-executable stack 기법이 코드 삽입 공격에 대한 효과적인 대응책이라는 확신이 들자 대부분의 제조사들은 이를 채택하고 하드웨어/소프트웨어적 지원을 제공하기 시작했다. 하지만 이는 과신이었다. Return-into-libc 공격에 대하여 Non-executable memory 는 그저 약간의 완화효과는 있을지언정 근본적인 해결책은 되지 못한다는 사실이 속속 밝혀지기 시작했다.

2005년, S. Krahmer는 “x86-64 buffer overflow exploits and the borrowed code chunks exploitation technique” 을 통해 전체 libc 함수들을 이용하지 않고 단지 작은 코드 조각 몇개를 여러번 재사용함으로써 buffer overflow를 일으킬 수 있다는 최초의 제안을 하였다. 또한 기존의 return-into-libc 공격은 x86 CPU에서만 잘 작동하였지 64bit 구조에서는 잘 적용되지 못했는데 이러한 단점 역시 Krahmer의 방법을 통해 개선할 수 있었다. 

2007년 ACM CCS 학회에서, Krahmer의 코드 조각(code snippet) 아이디어를 발전시킨, Hovav Shacham의 Return Oriented Programming이 모습을 드러내었다. [The Geometry of Innocent Flesh on the Bone: Return-into-libc without Function Calls (on the x86).] 코드 조각들을 사슬처럼 연결시킨 일명 가젯(Gadget)을 통해 기존에 있던 명령어들을 전혀 다른 형태로 수행시키는 기법을 발표하였다. 프로그램에서 return 명령어가 실행될 때마다 스택에 짧은 명령어 조각들이 하나씩 놓이게 되면서 실행고 이러한 연쇄반응이 프로그램의 흐름을 전혀 다른 방향으로 바꾸어버리는 것이다. 일명 ROP로 유명해진 이 기법은 다양한 시스템에서 모두 적용가능함이 확인되었다. (2007 ~ 2009)

  • x86 : The geometry of innocent flesh on the bone: Return-into-libc without function calls (on the x86)
  • SPARC : When good instructions go bad: Gen- eralizing return-oriented programming to RISC.
  • Atmel AVR : Code injection attacks on Harvard-architecture devices.
  • PowerPC : Developments in Cisco IOS forensics
  • Z80 : Can DREs provide long-lasting security? The case of return-oriented programming and the AVC Advantage.
  • ARM : Return oriented programming for the ARM architecture. M.S. thesis, Ruhr-Universit¨at Bochum

또한 Gadget을 자동으로 만드는 다양한 도구들도 개발되기 시작하였다.(2009)

한편, ROP가 return 명령어를 사용한다는 점에 착안하여 이를 방어하는 기법들이 제시되었으나, 다시 2010년에는 기존 ROP에서 이번에는 아예 Return 명령어조차 필요없는 [Return-oriented Programming without Returns]가 발표되었다. 

  • CHECKOWAY, S., DAVI, L., DMITRIENKO, A., SADEGHI, A.-R., SHACHAM, H., AND WINANDY, M. 2010. Return-oriented programming without returns. In Proceedings ofCCS 2010, A. Keromytis and V. Shmatikov, Eds. ACM Press, 559–72
  • Davi, Lucas, et al. Return-oriented programming without returns on ARM. Technical Report HGI-TR-2010-002, Ruhr-University Bochum, 2010.

최근에는 ROP 를 방어할 수 있는 다양한 기법들이 연구되고 있지만 아직 OS 제조사들이 공식적으로 채택한 묘안은 없다. bound checker나 Taint-tracking 등의 기술이 control-hijacking을 방어할 수 있는 효과적인 대안이 될 것으로 기대하고 있으나 오버헤드를 줄인 보다 실용적인 솔루션이 나타나길 기대한다.

Software Security Engineer

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

댓글

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