@OSG-PEDIY wrote:
Background(背景)——off-by-one(大小差一)错误介绍
详细了解请移步这里 off-by-one(Off-by-one error),大小差一错误是一类常见的程序设计错误。这方面有一个经典的例子OpenSSH.去Google搜索关键词“OpenSSH off-by-one”可以了解相关状况。具体来说,
if(id < 0 || id > channels_alloc)...
if(id < 0 || id >= channels_alloc)...
第二句应该是正确的写法。举个更通俗的例子:
int a[5],i;
for(i = 1;i < = 5;i++)
a[i]=0;
上述代码定义了长度为5的数组a,循环的目的是给数组元素初始化,赋值为0.但是,循环下标从1开始到5,出现了a[5]=0,这样的不存在的数组元素.这就是典型的“差一错误”(off-by-one).
Introduction(前言)
我认为我决定介绍该漏洞的理由是因为当我把它发在推特上时,我收到了一些私信说这个内核路径不存在漏洞(找不到漏洞在哪)或者该漏洞不能利用。另一个的理由就是我想在实际漏洞利用中尝试userfaultfd() 系统调用,我需要一个真实的UAF漏洞来进行实验。
首先,我不知道这个漏洞影响到哪些Linux发行版本的内核。我检查了ubuntu的最新发行版本Yakkety,发现其没有受该漏洞影响。漏洞在Linux kernel source tree被引入,在Linux kernel source tree中被修复。
因为我需要一个含有该漏洞的ubuntu内核,我在ubuntu16.04(x86_64)上编译了4.5.1内核。另外该漏洞仅仅影响像ubuntu一样默认使用AppArmor作为LSM(Linux安全模块)的发行版本,像centos使用SELinux就不受该漏洞的影响。
Vulnerability(漏洞介绍)
当写入/proc/self/attr/current 会使用内核中的proc_pid_attr_write() 函数。接下来介绍的代码是漏洞被引入之前的:
static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
struct inode * inode = file_inode(file);
char *page;
ssize_t length;
struct task_struct *task = get_proc_task(inode);length = -ESRCH; if (!task) goto out_no_task; if (count > PAGE_SIZE) [1] count = PAGE_SIZE; /* No partial writes. */ length = -EINVAL; if (*ppos != 0) goto out; length = -ENOMEM; page = (char*)__get_free_page(GFP_TEMPORARY); [2] if (!page) goto out; length = -EFAULT; if (copy_from_user(page, buf, count)) [3] goto out_free; /* Guard against adverse ptrace interaction */ length = mutex_lock_interruptible(&task-;>signal->cred_guard_mutex); if (length < 0) goto out_free; length = security_setprocattr(task, (char*)file->f_path.dentry->d_name.name, (void*)page, count);
...
查看完整版请移步看雪论坛
[翻译]CVE-2016-6187 Exploiting Linux kernel heap off-by-one 利用堆大小差一错误爆破Linux内核(上)
Posts: 1
Participants: 1