Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

渗透技巧 2年前 (2022) admin
595 0 0

本篇文章是在《Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之用户态调试》(参考链接:https://mp.weixin.qq.com/s/Rcp6bBivMcmH3GTm_Rvo-w)的基础上,继续深入到内核态进行调试。所以,各位看官可以先看看用户态调试的内容再看本篇内核态调试,当然,技术大牛可直接看内核态调试。

第一、准备环节-增加内核调试辅助语句:

首先,为了更好查看关键因素的变化:稍微做了两处修改:

第一处:splice前后,增加getchar和puts;

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

第二处:prepare pipe过程中,增加getchar和puts;

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

修改后代码执行结果如下:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

下面内容重点关注程序运行启动之后,该漏洞利用的两个关键要素:prepare_pipe函数、splice函数的内核态分析,此外对只读的suid文件的写入进行分析。

第二、关键因素-prepare_pipe函数的内核调试

这里的prepare_pipe函数有两个环节:第一个环节是write循环,第二个环节是read循环。

在第一个环节中,当程序执行到prepare_pipe函数中write循环,这里的内核态重点是关注flag信息,此时执行状态如下:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

对应的内核态执行内容:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

一步一步的调试,查看flags数值变化:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

结合如下的代码

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

可以看到517行将该flags设置为0x10,也就是can merge,这里以pipe->bufs[1]->flags为例,看内核流程和对应的变量。

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

这里只是显示了一次循环的结果,总计有16次循环,都会将此flags设置为can merge标记。


第二个环节就是进入到read循环,对应的执行状态和代码如下:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

Read完成后,原有的flag没有改变,依旧是0x10,最终prepare_pipe结束之前得到的flags信息如下:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

其中,显示3个bufs对应的flags的位置如下:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

从而可以看出,prepare_pipe已经顺利完成了flags的设置,全部设置为can merge的flag。

第三、关键因素-splice函数的内核调试

设置断点:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

对应此时的内核代码:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

以及对应的栈帧信息:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

进入该函数之后,可以查看flags,根据我们在用户态的推断,此时应该是0x10,gdb显示确实也是如此:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

此图说明,第一个要素此时已经准备好了。下面就是splice里面的关键的page的赋值

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

在尚未执行到buf-page=page时,这里的buf->page和page的值如下:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

完成page赋值之后,pipe的bufs[0],已经赋值为chsh这个suid文件的page了。

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

请记下此处的page信息0xffffea00002b3000,这里的page就是后续我们write函数的目的地址。只有能够write到这个page中,才能算是漏洞利用成功。

第四、将elfcode写入到只读suid文件对应的可读写的内存page中

设置write断点:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

对应的用户态代码如下:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

一步一步调试进入到内核态中if判断的分支中:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

此时,各个变量对应的数值如下:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

此时,该page就是/usr/bin/chsh这个suid文件在内存中的page,因为该page的flag为0x10,can merge,所以,后续的内容只要不超过这个page大小,就会继续在这个page中写入。这里的chars就是elfcode。大小只有0x196,加上1之后,不超过一个page的大小。所以,就直接覆写到该page中了。


      后续被调用的一系列操作就是本漏洞利用的重点,该处函数执行流会进入到如下代码段:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

此时453行的ret为0,接着执行copy_page_from_iter函数,查看此时的汇编代码:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

此时,就查看调用时的参数,终于可以确认该pipe_write函数的写入操作的目的就是位于0xffffea00002b3000的page。

此处执行的copy_page_from_iter的C代码如下:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

接着进入到copy_page_from_iter_iovec,

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

进入copy_page_from_iter_iovec函数的栈之后:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

然后查看该函数中关键的变量page和buf信息如下:

Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

此时,由上图可见,最核心的两个参数都已经准备好了,page就是我们前面得到的可以merge的page,而拷贝的内容就是buf,也是我们准备好的elfcode。该流程继续执行下去就完成了将elfcode拷贝到该page中,而该page对应着具有suid权限的/usr/bin/chsh文件。


至此,内核态最核心的两个关键要素以及写入suid文件对应的page这三个部分就差不多了,剩下的就参考用户态调试即可。还是要感谢发现这个漏洞的Max Kellermann以及国内众多针对这个漏洞的展开详细描述的各位专家。这两篇文章(用户态调试和内核态调试)如有不到之处,还请各位多指教。最后,完结散花。


原文始发于微信公众号(瑞不可当):Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试

版权声明:admin 发表于 2022年5月11日 下午5:43。
转载请注明:Gdb调试复现Dirty Pipe漏洞(CVE-2022-0847)之内核态调试 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...