Dirty PMD——New Exploitation Technique

相当于结合了 Dirty PageTable 和 Dirty PageDirectory ,算是有一点点创新,姑且厚着脸皮命个名并称之为一个 “New Exploitation Technique” :)

Introduction

笔者偶然整出个品相算不错的 0day ,闲着无聊 exploit 一下 RHEL ,靠这个备战一下明年的 GeekPwn ,希望别被别人先报了 :p

对于 Linux Kernel,当我们有一个 oob write vulnerability 时,如何利用?
笔者想尝试开发一个不依赖内核的通用 exp,所以更青睐 data-only attack
其实这个问题 @arttnba3 已经在 D^3CTF2023 的 d3kcache 中给出了解答:用 oob write 制造 pipe_buffer->page 的 overlap 从而转化为 page uaf
但笔者实际环境中操作下来有点困难:难以理想控制页风水,使得改写 pipe_buffer->page 后刚好 overlap with 另一个 pipe 的 pipe_buffer->page (也可能是菜😥)
如果这个 oob 的条件足够宽裕——允许使 oob offset 处递增 0x1000,Dirty PageTable 倒是可行,但在后半部分利用时面临着无法分配 sharing page 的问题:

  • 一般的 Linux 发行版中 /dev/dma_buf/system 需要 root 特权才能 open
  • 在 RHEL 的环境中关了 io_uring

也许还有其他笔者不知道的可用的 sharing page ,欢迎 dm 我😊

Technique

审视 Dirty PageTable 的流程,为什么需要 sharing page

  • 因为 pte entry 映射的 mmap 出来的一般的 anonymous page 位于 Movable 区域,而 pte page 处于 Unmovable 区域,将 pte entry 递增 0x1000 只能使得其指向另一个 anonymous page
  • sharing page 处于 Unmovable 区域,便可以控制物理页排布使 sharing pagepte page 相邻,将 pte entry 映射到 sharing page ,递增 pte entry 就能使其指向一个 pte page

Dirty PageTablepte page 作为 spray 以及 oob victim 的对象,如果 spray 的是 pmd page 呢?
触发一次缺页异常时,如果没有已有的 pmd 映射到这个地址,则会分配一个 pmd page 以及一个 pte page,写对应位置的 pmd entry 以及 pte entry 以建立映射
每隔一个 pmd page 映射的范围触发一次缺页异常,从而分配大量的 pmd page 以及 pte page,由于 pmd pagepte page 是交替分配的,那么大概率形成以下的物理页布局:

此时再修改 pmd entry ,能使其从原先指向的 pte page 到指向相邻的 pmd page

victim pmd entry 最终就会将 pte page 解析为可读写的 anon page,类似于 Dirty PageDirectory ,我们可以从 victim pmd entry 地址读写 pte page 的内容,再从 victim pte entry 读写,从而获得任意物理地址读写原语 :)

Drawback

pmd pagepte page 是交替分配的,所以将 pmd page 喷到相邻 vuln obj 处的概率为 1/2
不过笔者的 0day 可以多次触发,因此可以一直尝试
由于尝试失败后会破坏内核的数据结构且无法恢复,因此取得了 root 之后的环境不太稳定,由于以上原因该 Technique 并不能算优秀

!!Warning!!
不要在真机中尝试以避免不可逆的后果
笔者在研究过程中就打崩过他的虚拟机:

看起来是文件系统坏了,而且重启无法恢复😱
还好笔者之前拍了快照,但还是丢失了 exp 的进度

References