Linux Kernel一些基础知识

最常见的内核漏洞

  • NULL pointer dereference
  • kernel space stack overflow
  • kernel slab overflow
  • race conditions

一些漏洞利用比较简单,不需要准备Linux Kernel调试环境来写exploit,另外一些漏洞则需要Linux Kernel设计、工作原理和内存管理等方面的知识。

Kernel Expoit Mitigations

1.内核中与用户空间相同的防御措施:

  • DEP(存在)
  • Canary(存在)
  • ASLR(存在但是有限制)
  • PIE(不能直接使用)
  • RELRO(不能直接使用)

2.内核中新的防御措施:

  • MMAP_MIN_ADDR:mmap_min_addr是用来对抗null pointer dereference的,它不允许程序分配低内存.
  • KALLSYMS:/proc/kallsyms给出内核中所有symbol的地址,我们需要这个信息来写可靠的exploit,否则需要自己去泄露这个信息。kallsyms以前是全局可读的,现在它给没有权限的用户返回0.
  • RANDSTACK
  • STACKLEAK
  • SMEP/SMAP SMEP:Supervisor Mode Execution Protection
    SMAP:Supervisor Mode Access Protection

privilege escalation

1.在内核态调用commit_creds(prepare_kernel_cred(0)),返回用户态执行起shell:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void get_r00t() {
commit_creds(prepare_kernel_cred(0));
}
int main(int argc, char *argv) {
...
trigger_fp_overwrite(&get_r00t);
...
// trigger fp use
trigger_vuln_fp();
// Kernel Executes get_r00t()
...
// Now we have root
system("/bin/sh");
}

SMEP防预这种类型的攻击的方法是:如果处理器处于ring0模式,并试图执行有user数据的内存时,就会触发一个页错误。
SMAP工作原理相同,但是通常是在访问数据时。
这阻止不了漏洞,但会给开发exploit增加大量工作。
2.patch thread_info->addr为0xFFFFFFFF,突破内核地址空间的界限,得到任意读写的权限,然后改写struct cred。

参数传递

x86 Linux内核参数传递顺序有两种方式:

  • eax, edx, ecx, 栈传递
  • 直接栈传递

系统调用

经常需要在内核中查找系统调用的定义,比如shmget,在老版本内核中,系统调用通常定义为sys_shmget,可以直接通过相关符号查找。但新版本内核中,系统调用方式不同,采用了SYSCALL_DEFINE3(shmget...)的定义方式,其中3表示shmget有3个参数,参数的个数可以通过查看include/linux/syscalls.h文件中的定义得到。由于各系统调用的实现比较分散,查找时可以通过grep -nr "SYSCALL_DEFINE3(shmget" .在Linux内核源码中查找。