본문 바로가기

공부/보안

[dreamhack] System Exploitation 6강 - NX bit

반응형

6강 Linux Exploitation & Mitigation Part 1

6.4 NX bit의 등장

 

앞에서 프로그램 취약점을 이용해 실행 흐름을 조작한 뒤 스택 영역에 저장된 셸코드를 실행했다.

그러나 프로그램에서 스택 메모리는 코드실행 용도로 사용되는 것이 아니라, 데이터를 읽고 쓰는 데 사용되어 실행 권한이 필요가 없다. 이러한 이유로 프로그램의 공격을 어렵게 하기 위해, 메모리에 쓰기 권한과 실행 권한을 동시에 부여하지 않는 No-eXecute bit(NX bit)가 등장했다.

NX bit가 설정되어 있을 경우 쓰기 권한과 실행 권한이 동시에 있는 메모리 영역이 존재하지 않는다. 그래서 위의 예제처럼 셸코드를 스택 메모리에 저장해 실행 흐름을 스택으로 바꾸는 공격은 불가능하다.

프로그램에 스택 버퍼 오버플로우가 존재하면 실행 흐름을 임의의 주소로 바꾸는 것은 가능하다. NX bit가 적용되어 있는 상황에서 스택 메모리 등으로 실행 흐름을 직접 바꿔 공격하는 것의 불가능해 메모리의 실행 가능한 영역에 있는 코드를 활용해 익스플로잇을 해야 한다. C언어에서 printf 와 같은 라이브러리 함수가 사용될 때, 프로그램은 메모리에 로딩된 라이브러리 파일에서 호출된 함수의 주소를 찾아 실행한다.그래서 호출된 함수 이외에 system과 같이 익스플로잇에 좋은 함수 코드들도 함께 로딩된다.

1
2
3
4
5
6
7
// HelloWorld.c
// gcc -o HelloWorld HelloWorld.c -m32
#include <stdio.h>
int main(void){
  printf("Hello World!\n");
  return 0;
}
cs

HelloWorld 프로그램의 0xf7e03000 ~ 0xf7fb4000 영역이 libc.so.6 라이브러리 코드영역 주소이고, gdb 화면을 보면 프로그램에서 사용된 printf 함수 이외의 다른 함수들이 메모리에 존재한다는 것을 확인할 수 있다.

→ 프로그램에 버퍼 오버플로우 취약점이 존재할 때, 리턴 주소를 이와 같은 방법으로 알아낸 라이브러리 함수의 주소로 바꾸면 해당 함수를 호출할 수 있다.

Return To Libc(RTL)은 리턴 주소를 라이브러리 내에 존재하는 함수의 주소로 바꿔 NX bit를 우회하는 공격 기법이다.

리눅스 익스플로잇의 최종 목표는 셸 바이너리를 실행하는 것으로 libc.so.6 라이브러리에는 execve, execlp, execl, execvp, system, popen 등 프로그램을 실핼할 수 있는 함수들이 존재한다. 이 중 system 함수는 인자를 하나만 받아 익스플로잇할 때 자주 사용된다. system 함수의 인자는 실행할 셸 명령어 문자열의 주소이기 때문에, 만약 "/bin/sh" 문자열의 주소를 system 함수의 인자로 넘겨준 후 호출하면 /bin/sh 바이너리가 실행된다.

NX bit가 추가된 앞 예제는 스택의 셸코드를 실행시킬 수 없다. 이전 익스플로잇에서는 스택 내의 셸코드를 실행시켜 execve 시스템 콜 호출이 목표였다면, RTL의 목표는 라이브러리 내 존재하는 system 함수를 호출해 system("/bin/sh")을 실행하는 것이다.

buf 배열부터 vuln 함수의 리턴 주소 위치까지는 36바이트다. 실행 결과 eip 레지스터가 0x42424242로 바뀌었고, ret 하기 전 스택 포인터인 esp-4 메모리에 0x42424242가 저장된 것을 볼 수 있다.

만약 인자가 3개인 함수 func(1, 2, 3)을 호출한다면, func+0 시점에서의 스택 메모리 상태는 아래와 같다.

RTL에서, 리턴 주소에 호출 함수 주소를 덮어쓴 후 ret 하면 eip 레지스터가 덮은 값이 되고, esp 레지스터는 리턴 주소의 위치+4 가 된다. 즉, 함수 시작 부분에서 인자 위치는 esp+4가 되고, 호출된 함수의 리턴 주소가 저장된 위치는 esp+0 이다.

"A" * 36 + (system 함수 주소) + "BBBB" + ("/bin/sh" 주소)

위는 익스플로잇 코드 구조로 BBBB 는 system 함수가 종료된 후 리턴할 주소로 system("/bin/sh")를 실행하는 것이 목표이기 때문에 임의의 값을 적었다.

RTL에 필요한 주소를 찾아야 한다. system("/bin/sh") 을 호출하기 위해 system 함수의 주소와 /bin/sh 문자열의 주소를 알아야한다. 이들을 gdb를 통해 알아볼 수 있다.

익스플로잇 코드이다.

`python -c 'print "A"*36+"\xb0\xcd\xe3\xf7"+"BBBB"+"\x0b\xdb\xf5\xf7"'`

[+] NX bit 가 설정되어 있는지 확인 방법

바이너리의 NX bit 적용 여부를 ELF 바이너리 분석 도구인 readelf 를 사용하는 등 스택 메모리의 권한을 검사할 수 있다.

  • readelf 를 이용한 NX bit 체크

  • checksec

 

 

 

 

Review(6강 Linux Exploitation & Mitigation Part 1)

ELF 디버깅

- gdb에 존재하는 여러 명령어들을 사용해 ELF 바이너리를 디버깅 하고, 프로세스 PID를 이용해 gdb를 attach 시켜 실행 중인 프로세스를 디버깅하는 방법을 알았다.

RET Overwrite

- 스택 버퍼 오버플로우 취약점이 존재할 떄 스택의 리턴 주소를 덮어 실행 흐름을 바꾸는 공격방법으로 실행 흐름을 공격자가 제작한 셸코드로 바꾸어 임의의 코드 실행 방법을 알았다.

NOP Sled

- 익스플로잇의 확률을 높여주는 NOP Sled 기법으로 수많은 NOP 명령어를 스택 등의 메모리에 저장한 후 NOP 명령어 중간으로 점프하면 NOP 명령어들을 넘어 NOP Sled 뒤 공격자의 셸코드 실행한다.

NX bit

- 메모리에 쓰기 권한과 실행 권한을 동시에 부여하지 않도록 하는 보호기법으로 라이브러리 메모리에 존재하는 함수를 이용하여 공격하는 RTL을 통해 NX bit를 우회하는 방법을 배웠다.

반응형