Intro
커널 영역도 유저 영역처럼 보호기법이 존재한다. 많이 어려울줄 알았는데, 조금 찾아보니 다행히 대동소이한 것 같아서 핵심만 요약해보려 한다. 아직 보호기법에 따라 사용해야하는 공격기법은 공부하지 않았기 때문에, 보호기법에 중점을 두고 작성했다.
Checksec
/proc/cpuinfo &/etc/default/grub 파일 확인
cat /proc/cpuinfo | grep flags위 명령어로 smep, smap 확인하고, /etc/default/grub에서 kaslr 확인
qemu 스크립트 확인
qemu 스크립트에 아래 옵션들로 확인 가능하다.
-append "••• nokaslr •••"
-cpu smep,smapKASLR
유저 영역 보호기법인 ASLR 앞에 Kernel이 붙은 보호기법이다. 말 그대로 커널 영역 주소 랜덤화다.
커널이 실행되기 전 부트로더에서 세팅된다.
적용 여부는 qemu 스크립트에 옵션으로 준다. 아래 스크립트의 nokaslr 부분이다.
#!/bin/sh
qemu-system-x86_64 \
-m 64M \
-nographic \
-kernel bzImage \
-append "console=ttyS0 loglevel=3 oops=panic panic=-1 nopti nokaslr" \
-no-reboot \
-cpu qemu64 \
-smp 1 \
-monitor /dev/null \
-initrd debugfs.cpio \
-net nic,model=virtio \
-net user우회 방법은 ASLR과 마찬가지로 임의의 주소를 leak해서 offset을 계산해서 해결 가능하다.
/proc/kallsyms 파일에 커널의 모든 심볼 주소를 담고 있어서 이를 토대로 계산해주면 된다(libc 처럼).
해당 파일 내에 base address는 _text 심볼의 주소다.

SMEP
커널 영역에서 유저 영역의 실행 권한을 제한
ring 0 권한일 때 ring 3와 관련된 코드를 실행할 수 없게 하는 기법인데, NX Bit 보호기법과 비슷하다.
cr4 레지스터에 SMEP를 제어하는 비트가 있는데, 이 비트를 0으로 만들면 해제가 가능하다.
커널 영역 ROP로 우회가 가능하며, gadget은 vmlinux 이미지에서 구할 수 있다.
pwndbg> i r
rax 0xffffffff81b2c390 -2118990960
rbx 0x0 0
rcx 0x0 0
rdx 0x232 562
rsi 0x83 131
rdi 0x0 0
rbp 0x0 0x0
rsp 0xffffffff82403eb0 0xffffffff82403eb0
•••
cr0 0x80050033 [ PG AM WP NE ET MP PE ]
cr2 0x24fdc78 38788216
cr3 0x1d92e000 [ PDBR=121134 PCID=0 ]
cr4 0x1006f0 [ SMEP OSXMMEXCPT OSFXSR PGE MCE PAE PSE ]
•••추가로 커널 영역에서 유저 영역의 실행 권한을 제한하기 때문에 페이로드를 커널 영역에 넣어놓고 스택 피봇팅을 이용한 방법으로도 우회가 가능하다.
커널 영역에서 특정 주소에 접근할 수 있을 때, 유저 영역에서 mmap을 이용해 해당 영역을 할당하고, 페이로드를 해당 영역에 작성해둔 다음에 return 해버리면 된다.
SMAP
SMEP + Read/Write 권한도 제한.
이 보호기법 또한 cr4 레지스터에서 제어하며, 이를 0으로 만들면 해제할 수 있다.
SMEP처럼 stack based BOF가 발생하면 단순하게 ROP로 우회 가능하다. 하지만 이런 경우는 굳이 SMAP를 설정하지 않기 때문에 거의 보기 힘들다.
다른 우회 방법으로는 slab 객체 크기의 커널 힙 할당 및 UAF가 가능한 경우에는 fork() 호출 시 커널 힙에 할당 되는 cred 구조체의 멤버를 수정하여 권한 상승을 할 수 있다.
해당 기법을 이용한 문제 풀이
KADR
일반 유저가 커널의 심볼을 볼 수 없도록 제한.
/ $ cat /proc/kallsyms | grep text
0000000000000000 T _stext
0000000000000000 T _textrootfs 파일의 init 파일 안에 설정되어 있다.
echo 2 > /proc/sys/kernel/kptr_restrict2 : 모두에게 표시 안함
1 : 권한 있는 유저에게만 표시
0 : 모두에게 표시
커널 힙과 관련된 취약점의 경우 user 권한과 root 권한일때의 heap 할당 방식이 다르기 때문에 offset 계산 후 user 권한으로 다시 디버깅을 해야한다.
SSP
Canary와 동일
Leak으로 우회하면 된다.
KPTI
커널 영역 ←> 유저 영역 간 전환이 발생할 때, 각자의 페이지 테이블을 사용한다. 이 때 최소한의 커널 주소만 포함되도록 하는 보호기법이다.
qemu 스크립트에서 -cpu kvm64가 적용되어 있는 경우에만 해당한다.
앞에 나온 다른 보호기법에서는 ROP 페이로드를 작성할 시 swapgs와 iretq 가젯을 사용하는데, 이 보호기법을 우회할 때는 swapgs_restore_regs_and_return_to_user_mod 함수를 추가한다.
해당 함수는 커널 영역에서 유저 영역으로 전환될 때 호출되는 함수인데, 페이지 테이블을 분리한다. 함수 내에서 페이지 테이블을 분리하고 나면, swapgs, iretq를 알아서 호출한다.