CVE-2022-0847 DirtyPipe漏洞分析


CVE-2022-0847 DirtyPipe漏洞分析

文章插图
 
前言 
 
CVE-2022-0847 DirtyPipe脏管道漏洞是linux内核中的一个漏洞,该漏洞允许写只读文件,从而导致提权 。
 
 
调试环境 
 
  • ubuntu 20.04
  • Linux-5.16.10
  • qemu-system-x86_64 4.2.1
 
 
漏洞验证 
 
首先创建一个只读文件foo.txt,并且正常情况下是无法修改该可读文件,但是利用了DirtyPipe漏洞后发现可以将字符aaaa写入到只读文件中
 

CVE-2022-0847 DirtyPipe漏洞分析

文章插图
 
漏洞分析 
【CVE-2022-0847 DirtyPipe漏洞分析】 
poc作为切入点,分析漏洞成因
 
 
首先poc创建了一个管道,管道缓冲区的默认大小为4096,并且拥有16个缓存区,因此再创建管道之后,poc首先要做的是将这16个管道缓冲区填满 。
 
 
...if (pipe(p)) abort();const unsigned pipe_size = fcntl(p[1], F_GETPIPE_SZ);static char buffer[4096];for (unsigned r = pipe_size; r > 0;) {unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;write(p[1], buffer, n);r -= n;}... 
 
在进行管道写的操作时,内核是采用pipe_write函数进行操作,这里截取了关键部分,在进行管道写的时候会判断通过函数is_packetized去判断是否为目录属性,如果不是则将缓冲区的标志位设置为PIPE_BUF_FLAG_CAN_MERGE,这个标志位非常关键,是导致漏洞成因,因此poc为了使16个管道缓冲区都设置PIPE_BUF_FLAG_CAN_MERGE标志位,因此选择循环16次,并且将每个管道缓冲区都写满 。
 

CVE-2022-0847 DirtyPipe漏洞分析

文章插图
 
随着poc将管道内的数据全部读出,为了清空管道缓冲区,在进行管道读的过程中,内核采用的是pipe_read函数,在整个管道读的过程中是不会修改管道的标志位的,因此PIPE_BUF_FLAG_CAN_MEGE标志位依旧存在
 
 
...for (unsigned r = pipe_size; r > 0;) {unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;read(p[0], buffer, n);r -= n;}... 
 
紧接着是触发漏洞的关键函数,splice函数,用于移动数据,此时fd指向我们想读取的文件,对应上述的foo.txt只读文件,p[1]指向的是我们的管道符 。
 
 
...ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0);... 
 
在调用splice函数时,内核在某个阶段会调用copy_page_to_iter函数,可以看到当管道满了之后就没办法通过splice函数往管道内继续输入数据,那么splice函数就无法正常执行了,因此需要清空管道内的数据 。
 

CVE-2022-0847 DirtyPipe漏洞分析

文章插图
 
后面则到达了漏洞发生的代码,由于我们使用splice函数进行数据的移动,在内核中不是选择将数据直接从文件中拷贝到管道中,而是将文件所在的物理页直接赋值给管道缓冲区所对应的页面 。
 

CVE-2022-0847 DirtyPipe漏洞分析

文章插图
 
这里记录一下物理页的地址
 

CVE-2022-0847 DirtyPipe漏洞分析

文章插图
 
最后就是再次调用管道写的操作,但是这里实际会写入只读文件内部
 
 
...nbytes = write(p[1], data, data_size);... 
 
【----帮助网安学习,需要网安学习资料关注我,私信回复“资料”免费获取----】
① 网安学习成长路径思维导图
② 60+网安经典常用工具包
③ 100+SRC漏洞分析报告
④ 150+网安攻防实战技术电子书
⑤ 最权威CISSP 认证考试指南+题库
⑥ 超1800页CTF实战技巧手册


推荐阅读