x64 Linux 虚拟内存分布图
前段时间做linux内核pwn时,碰到一个很有意思的虚拟内存区域 —— cpu_entry_area mapping(0xfffffe0000000000~ 0xfffffe7fffffffff)。这个区域未开启随机化,在利用时可以用来:
- 泄露内核代码段地址信息,绕过KASLR
- 地址空间有可写部分,rop等数据可以布置到该空间
- 0xfffffe0000010f58可作为栈迁移的目的地(DB exception stack),需结合硬件断点(hardware breakpoint)和DB异常(debug exception)
这么强大的一个区域居然从来没关注过,来看看linux官方给出的虚拟内存分布图,会不会还存在一些尚未关注到的危险区域呢?
为了了解以上各区间存在的意义及其特性,新起这篇博客专门记录学习过程,一点点更新。
user-space virtual memory
用户空间的虚拟内存空间,每个进程都有自己独立的内存空间,struct mm_struct
cpu_entry_area mapping
区间:0xfffffe0000000000 ~ 0xfffffe7fffffffff
大小:2 TB
随机化:从linux 6.2开始,对cpu_entry_area做了随机化,早期版本无随机化。但未对idt区域随机化,因此,依然可以通过这个位置泄露内核地址。
内容:存放IDT表和n个 struct cpu_entry_area结构体,每个cpu对应一个cpu_entry_area结构体。以linux5.15.119为例,结构体定义如下
1 | struct cpu_entry_area { |
可以看到,结构体中包含:
- the GDT
- the entry stack :每个cpu有一个,用于处理用户态到内核的上下文切换。
- the TSS
- the exception stacks :cpu处理某些中断和异常时会用到这里面的栈,一共有7种类型。对应到tss_struct结构体种的
tss->x86_tss.ist[7]
,即Interrupt Stack Table 中断栈表(IST)。 - debug stores and buffers
该结构体在整个mapping区域布局如下图所示(老版本内核的偏移跟这个不一样,DB_stack\DF_stack等栈大小是0x1000):
在漏洞利用中需要关注的是exception stacks中DB_stack这段,它是内核空间的地址,同时用户态也能将数据布置到上面。用户态通过ptrace为子进程设置硬件断点,并在子进程中触发该硬件断点,便能将此时子进程的寄存器内容压入DB_stack中。
代码层面如何操作呢?如下代码可将用户态寄存器数据布置到cpu_entry_area的DB stack中
1 |
|
以上程序执行完毕后,调试查看内核信息,成功将用户态数据放入DB stack
参考:
P0: Exploiting CVE-2022-42703 - Bringing back the stack attack
pray77: 跟cpu_entry_area相关的一个题 - sycrop和sycrpg
veritas501: 一种借助硬件断点的提权思路分析与演示
sholck: cea区域前0x1000空间映射到 IDT table
stackexchange - what is cpu_entry_area?