1. 소개
이번 글에서는 커널의 대표적인 보호 기법인 SMEP, SMAP, KASLR, KPTI 등에 대해 알아본다.
기본적인 보호 기법은 사용자 공간에서와 비슷하며 커널 공간 특유의 취약점을 보호하는 기법도 존재한다.
이 글에서는 보호 기법에 대해서만 알아보고 Exploit Tech는 다른 글에서 다룰 예정이다.
2. SMEP
SMEP(Supervisor Mode Execution Prevention)
SMEP은 커널의 대표적인 보호 기법으로, 사용자 공간의 NX(No Execute)와 비슷한 역할의 보호기법이다. 커널 공간에서 코드를 실행할 때, 실행할 코드가 유저 공간의 코드 혹은 유저 공간에서 접근 가능한 코드라면 실행을 못하게 막는 보호 기법이다.
SMEP은 하드웨어 차원의 보안 기법으로 CR4 레지스터의 21번 비트가 켜지면 SMEP이 활성화 된다.
Qemu 안에서 SMEP이 활성화 되었는지 확인 하려면 /proc/cpuinfo를 확인하면 된다.
$ cat /proc/cpuinfo | grep smep
Qemu에서 사용법은 qemu 실행 시 다음 명령어를 추가하면 된다.
-cpu kvm64, +smep
3. SMAP
SMAP(Supervisor Mode Access Prevention)
SMAP은 SMEP과 같이 커널의 대표적 보호 기법이다. 유저 공간에서 커널 공간의 주소에 있는 값을 읽는 것은 보안상 제한되어 있다. 하지만 커널 공간에서 유저 공간의 값을 참조 하는것은 제한 되어있지 않은데, 이를 방지하는 것이 SMAP이다.
예를들어 커널 공간은 매우 크기 때문에 다음과 같은 gadget이 존재할 수 있다.
mov esp, 0x12345678; ret;
이때, 만약 유저 공간에서 mmap을 통해 ROPchain을 구성한다 하면 다음과 같은 코드가 만들어 진다.
void *p = mmap(0x12340000, 0x10000, 7, ...);
unsigned long *chain = (unsigned long*)(p + 0x5678);
*chain++ = rop_pop_rdi;
*chain++ = 0;
...
control_rip(mov_esp_12345678h);
SMEP 관점에서 보았을 때, mmap으로 할당된 낮은 주소의 공간은 실행에 제한이 걸리지 않는다. 하지만 mmap을 통해 해당 주소에는 rop chaning 코드가 존재하고, rip를 이곳으로 조작할 시 실행할 수 있는 것이다.
이를 SMAP을 통해 보호하게 된다면 유저 공간에서는 0x12345678 주소에 값을 적었지만 커널 공간에서 해당 값을 읽을 수 없게 되어 Stack Pivoting을 방지할 수 있게된다.
또 반대로 커널 공간 주소에 있는 값을 유저 공간의 버퍼로 복사하는 등의 AAR / AAW 공격으로부터 보호할 수 있다.
SMAP도 하드웨어 차원의 보안 기법으로 CR4 레지스터의 22번 비트가 켜지면 활성화 된다.
Qemu 안에서 SMAP이 활성화 되었는지 확인 하려면 /proc/cpuinfo를 확인하면 된다.
$ cat /proc/cpuinfo | grep smap
Qemu에서 사용법은 qemu 실행 시 다음 명령어를 추가하면 된다.
-cpu kvm64, +smap
4. KASLR
KASLR(Kernel Address Space Layout Randomization)
유저 공간에서 ASLR로 인하여 스택 주소, libc base 주소가 랜덤화 되어 공격하기 어렵게 만들었 듯이 커널 공간에도 똑같이 ASLR이 존재한다. 단, 커널은 부팅시 KASLR이 1회 설정되고 재부팅을 하기 전까지는 매핑된 주소가 바뀌지 않는다.
또, 이러한 특징 때문에 대부분의 모듈, 드라이버 들이 주소를 얻을 수 없는 환경이더라도 단 한개의 모듈에서 주소가 누설된다면 모든 커널 공간의 base address를 알 수 있게된다.
KASLR은 기본적으로 적용되게 설정되어 있어서 비활성화 하기위해서는 qemu 실행시 다음 코드를 추가해주면 된다.
-append "... nokaslr ..."
이전 글에서 사용한 LK01 예제파일 에서 run.sh에는 위 코드가 포함되어 있어 aslr이 적용되어 있지 않다.
FGKASLR(Function Granular KASLR)
KASLR의 강화 버전으로, 커널 공간의 함수 별로 주소를 랜덤화 하는 보호 기법이다. 하지만 데이터 섹션과 같은 일부분 랜덤화가 되지 않는 공간도 존재한다.
현재는 따로 설정하지 않는이상 KASLR만 기본적으로 설정되고 FGKASLR은 사용되지 않는다.
5. KPTI (KISER)
KPTI(Kernel Page-Table Isolation)
KPTI란 Meltdown 취약점의 대응 방안으로 나오게된 보호 기법이다. Meltdown 취약점은 대표적인 부채널 공격 취약점으로 간단하게 설명하면 아키텍처 즉, 하드웨어 적인 부분에서 추측 명령 실행, 비순차적 명령 처리 기술의 취약한 점을 이용하여 권한 상승 혹은 커널 공간의 작업을 외부에서 읽을 수 있게 되는 취약점 이다.
KPTI는 가상주소에서 물리주소로 변환할 때 사용되는 page-table을 커널 공간과 유저 공간으로 구분해주는 역할을 하는데, 일반적인 exploit에 큰 문제가 되지는 않지만 Kernel ROP 진행 후 ret2usr 과정 등에서 보호 기법으로 인해 차단될 수 있다.
Meltdown의 대응 방안으로 나온 보호 기법이라 해서 하드웨어 차원의 보호 기법 같지만 KPTI는 소프트웨어 차원의 보호 기법이고 다음 코드를 qemu 실행시 추가하면 켜고 끌 수 있다.
# kpti on
-append "... pti=on ..."
# kpti off
-append "... pti=off ..."
-append "... nopti ..."
qemu 머신 내에서는 /sys/devices/system/cpu/vulnerabilities/meltdown 파일을 확인하면 적용 되어있는지 확인할 수 있다.
# cat /sys/devices/system/cpu/vulnerabilities/meltdown
Mitigation: PTI
6. KADR
KADR(Kernel Address Display Restriction)
커널에서는 함수의 이름과 주소 정보 등을 /proc/kallsyms 파일 혹은 드라이버에 따라서 printk 함수 등을 사용하여 디버깅 로그를 출력하고 이를 dmesg 명령 등으로 확인 할 수 있다.
이러한 함수의 정보를 수준에 따라 보호하는 기법이 여럿 존재하는데 통상 KADR이라고 부른다.
리눅스에서는 /proc/sys/kernel/kptr_restrict 파일의 값에 따라 보호 정도가 설정된다.
kptr_restrict의 값이 0인 경우 아예 주소가 숨겨지지 않으며 1인 경우, CAP_SYSLOG 권한을 가진 사용자 에게만 주소가 표시된다. 마지막으로 2인 경우 어떠한 사용자도 주소를 표시하지 않는다.
7. 정리
여기까지 커널의 다양한 보호 기법에 대해서 개념과 설정방법 등에 대해서 알아보았다. 다음 글에서는 커널의 모듈과 exploit 기초인 Holstein 모듈에 대해서 정리할 예정이다.
'Kernel' 카테고리의 다른 글
[Kernel] KROP & KPTI (0) | 2024.03.15 |
---|---|
[Kernel] Kernel Stack Overflow & Commit_creds (0) | 2024.02.18 |
[Kernel] Holstein Module (1) | 2024.02.12 |
[Kernel] qemu를 사용한 환경 세팅 (1) | 2023.12.18 |
[Kernel] Introduce Kernel (0) | 2023.12.15 |