0x0 漏洞信息
https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2012-0056
0x1 漏洞描述
Linux通过一个特殊字符设备/proc/$pid/mem把每个进程的虚拟内存暴露为一个文件.出于安全考虑,读写这个文件的权限被严格限制,拥有写入权限的只有内存的所属进程.但是攻击者可以打开目标进程的mem设备,把它复制到进程的stdout和stderr.当stdout重定向到与虚拟内存相关的字符设备时,攻击者可以写入其他程序内存,但是写入的地址是未知的.
0x2 代码分析
static int mem_open(struct inode* inode, struct file* file)
{
file->private_data = (void*)((long)current->self_exec_id);
file->f_mode |= FMODE_UNSIGNED_OFFSET;
return 0;
}
//mem写入
static ssize_t mem_write(struct file * file, const char __user *buf,size_t count, loff_t *ppos)
{
struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
mm = check_mem_permission(task);
copied = PTR_ERR(mm);
if (IS_ERR(mm))
goto out_free;
if (file->private_data != (void *)((long)current->self_exec_id))
goto out_mm;
}
//校验权限
static struct mm_struct *__check_mem_permission(struct task_struct *task)
{
struct mm_struct *mm;
mm = get_task_mm(task);
if (!mm)
return ERR_PTR(-EINVAL);
if (task == current)
return mm;
if (task_is_stopped_or_traced(task))
{
int match;
rcu_read_lock();
match = (ptrace_parent(task) == current);
rcu_read_unlock();
if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH))
return mm;
}
mmput(mm);
return ERR_PTR(-EPERM);
}
void setup_new_exec(struct linux_binprm * bprm)
{
current->self_exec_id++;
flush_signal_handlers(current, 0);
flush_old_files(current->files);
}
系统会检查打开/poc/$pid/mem的程序的self_exec_id是否与当前运行的程序相同,一个进程使用exec()后self_exec_id会自动加一,以此来保护内存不会被别的程序修改.
0x3 如何利用
先fork()子进程来保存进程的mem文件到CMSG_DATA,然后父进程使用dup(2)创建2号fd,接着dup2(mem,2)将mem的内容dup2给2号fd,这时2号fd指向了/poc/$pid/mem的fd.
0x4 Poc
/* mempodroid - implementat