본문 바로가기

보안

[시스템해킹] NX & ASLR

NX(No-eXecute): 실행에 사용되는 메모리 영역과 쓰기에 사용되는 메모리 영역을 분리하는 보호 기법
인텔-XD(eXecute Disable), AMD-NX, 윈도우-DEP(Data Execution Prevention, ARM-XN(eXecute Never)

 

- 코드 영역에 쓰기 권한이 있으면 공격자는 코드를 수정하여 원하는 코드가 실행되게 할 수 있고,

- 스택, 데이터 영역에 실행 권한이 있으면 system 함수 등을 실행시켜 공격을 시도할 수 있음

- CPU가 NX를 지원하면 컴파일러 옵션을 통해 바이너리에 NX를 적용할 수 있으며, NX가 적용된 바이너리는 실행될 때 각 메모리 영역에 필요한 권한만을 부여받음

- NX가 적용된 바이너리는 코드 영역 외에는 실행 권한이 없음

 

ASLR(Address Space Layout Randomization): 바이너리가 실행될 때마다 스택, 힙, 공유 라이브러리 등을 임의의 주소에 할당하는 보호 기법

 

//ASLR 예제 코드

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
  char buf_stack[0x10];                   // 스택 버퍼
  char *buf_heap = (char *)malloc(0x10);  // 힙 버퍼

  printf("buf_stack addr: %p\n", buf_stack);
  printf("buf_heap addr: %p\n", buf_heap);
  printf("libc_base addr: %p\n",
         *(void **)dlopen("libc.so.6", RTLD_LAZY));  // 라이브러리 주소

  printf("printf addr: %p\n",
         dlsym(dlopen("libc.so.6", RTLD_LAZY),
               "printf"));  // 라이브러리 함수의 주소
  printf("main addr: %p\n", main);  // 코드 영역의 함수 주소
}
$ gcc addr.c -o addr -ldl -no-pie -fno-PIE

$ ./addr
buf_stack addr: 0x7ffcd3fcffc0
buf_heap addr: 0xb97260
libc_base addr: 0x7fd7504cd000
printf addr: 0x7fd750531f00
main addr: 0x400667
$ ./addr
buf_stack addr: 0x7ffe4c661f90
buf_heap addr: 0x176d260
libc_base addr: 0x7ffad9e1b000
printf addr: 0x7ffad9e7ff00
main addr: 0x400667
$ ./addr
buf_stack addr: 0x7ffcf2386d80
buf_heap addr: 0x840260
libc_base addr: 0x7fed2664b000
printf addr: 0x7fed266aff00
main addr: 0x400667

 

-> 코드 영역의 main 함수를 제외한 다른 영역의 주소들은 실행할 때마다 변경됨

-> libc_base와 printf 주소 차는 항상 같음

-> ASLR이 적용되면 라이브러리는 임의 주소에 매핑되는데, 파일을 그대로 매핑하므로 심볼들까지의 거리(offset)은 동일

 

공격 방법

- NX와 ASLR이 적용되면 스택, 힙, 데이터 영역에는 실행 권한이 제거되며 할당 주소가 계속 변함

- 반면, 바이너리의 코드가 존재하는 영역은 여전히 실행 권한 존재하며 할당 주소도 고정

- 코드 영역에는 유용한 코드 가젯들과 함수가 포함되어 있음

- NX와 ASLR을 우회해 공격할 수 있는 방법; Return-to-Libc(RTL), Return Oriented Programming(ROP)

 

드림핵 시스템해킹 로드맵 참고