Windows内核利用小总结
字数 2436 2025-08-18 11:36:48
Windows内核利用技术深度解析
1. 令牌(Token)提权技术
1.1 基本原理
Windows进程的访问权限由令牌(Token)控制,存储在EPROCESS结构的Token字段中。通过将System进程的Token替换到目标进程的EPROCESS结构中,可以实现提权。
1.2 关键实现步骤
- 定位System进程和目标进程的EPROCESS结构
- 获取System进程的Token值
- 修改目标进程EPROCESS中的Token字段
- 注意Token在EPROCESS中的偏移量随Windows版本变化(如1809版本偏移为0x360)
1.3 Token结构特点
Token是一个_EX_FAST_REF结构,由于内存对齐要求,指向内核对象的指针最低4位总是0。
2. PreviousMode利用技术
2.1 PreviousMode作用机制
- UserMode(1): 进行地址验证,防止用户态写入内核内存
- KernelMode(0): 跳过地址验证,允许任意内核内存写入
2.2 利用条件
需要能够修改KTHREAD结构中的PreviousMode字段,将其从UserMode改为KernelMode。
3. Windows内核池利用技术
3.1 池分配基础
主要分配函数:
void *ExAllocatePoolWithTag(POOL_TYPE PoolType, size_t NumberOfBytes, unsigned int Tag);
void ExFreePoolWithTag(void *P, unsigned int Tag);
3.2 POOL_TYPE类型
| 类型 | 值 | 描述 |
|---|---|---|
| NonPagedPool | 0 | 不可分页内存 |
| PagedPool | 1 | 可分页内存 |
| NonPagedPoolMustSucceed | 2 | 必须成功分配 |
| NonPagedPoolCacheAligned | 4 | 缓存对齐的非分页池 |
| PoolQuota | 8 | 使用配额机制 |
| NonPagedPoolNx | 0x200 | 不可执行的非分页池 |
3.3 POOL_HEADER结构
struct POOL_HEADER {
char PreviousSize; // 前一个块大小/16
char PoolIndex; // PoolDescriptor数组索引
char BlockSize; // 当前块大小/16
char PoolType; // 池类型信息
int PoolTag; // 池标签
Ptr64 ProcessBilled; // 指向分配进程的KPROCESS指针
};
3.4 利用技术演变
- Win7及之前:覆盖ProcessBilled指针实现任意指针解引用
- Win8引入:ExpPoolQuotaCookie保护机制,验证KPROCESS指针有效性
- Win10 19H1后:引入Segment Heap,改变了POOL_HEADER利用方式
4. Segment Heap利用技术
4.1 段堆后端类型
- Segment Backend:分配128KB-7GB内存块
- Variable Size Backend:分配512B-128KB内存块
- Low Fragmentation Heap Backend:分配1B-512B内存块
- Large Alloc:超大内存分配
4.2 关键结构
_SEGMENT_HEAP:段堆主结构_HEAP_PAGE_SEGMENT:段头结构_HEAP_PAGE_RANGE_DESCRIPTOR:页范围描述符
4.3 幽灵块(Ghost Chunk)技术
- 通过堆溢出修改下一个块的POOL_HEADER
- 设置PoolType中的CacheAligned位
- 控制PreviousSize字段指向伪造块
- 在合法块中间创建虚假块(幽灵块)
4.4 利用步骤
- 堆喷创建合适的内存布局
- 触发漏洞覆盖POOL_HEADER
- 创建幽灵块实现UAF
- 通过管道属性操作实现任意读写
5. I/O Ring利用技术
5.1 I/O Ring基本结构
typedef struct _IORING_OBJECT {
USHORT Type;
USHORT Size;
NT_IORING_INFO Info;
PSECTION SectionObject;
PVOID KernelMappedBase;
PMDL Mdl;
PVOID MdlMappedBase;
ULONG_PTR ViewSize;
ULONG SubmitInProgress;
PVOID IoRingEntryLock;
PVOID EntriesCompleted;
PVOID EntriesSubmitted;
KEVENT RingEvent;
PVOID EntriesPending;
ULONG BuffersRegistered;
PIORING_BUFFER_INFO BufferArray; // RegBuffers
ULONG FilesRegistered;
PHANDLE FileHandleArray;
} IORING_OBJECT;
5.2 利用原理
- 通过漏洞覆盖IoRing->RegBuffers指向伪造缓冲区数组
- 使用伪造数组指定内核地址进行读写
- 22H2后需要使用IOP_MC_BUFFER_ENTRY结构
5.3 IOP_MC_BUFFER_ENTRY结构
typedef struct _IOP_MC_BUFFER_ENTRY {
USHORT Type;
USHORT Reserved;
ULONG Size;
ULONG ReferenceCount;
ULONG Flags;
_LIST_ENTRY GlobalDataLink;
PVOID Address; // 目标地址
ULONG Length; // 长度
CHAR AccessMode;
ULONG MdlRef;
struct _MDL* Mdl;
KEVENT MdlRundownEvent;
PULONG64 PfnArray;
BYTE PageNodes[1];
} IOP_MC_BUFFER_ENTRY;
5.4 典型利用流程(CVE-2023-21768)
- 创建I/O Ring和命名管道
- 获取I/O Ring对象地址
- 覆盖RegBuffers和RegBuffersCount
- 构造伪造的IOP_MC_BUFFER_ENTRY数组
- 通过BuildIoRingReadFile/BuildIoRingWriteFile进行内核读写
- 替换目标进程Token实现提权
6. 防御机制与绕过技术
6.1 主要防御机制
- ExpPoolQuotaCookie:保护ProcessBilled指针
- NonPagedPoolNx:不可执行内存保护
- Segment Heap:改变内存管理方式
- 22H2的IOP_MC_BUFFER_ENTRY:更严格的缓冲区验证
6.2 绕过技术
- 利用PoolType中的CacheAligned位
- 通过幽灵块实现UAF
- 结合管道属性操作实现任意读写
- 使用I/O Ring机制实现内核内存操作
7. 实用工具与技术
7.1 关键API
NtQuerySystemInformation:获取系统信息(如SystemBigPoolInformation)NtFsControlFile:操作管道属性CreateIoRing:创建I/O RingBuildIoRingReadFile/BuildIoRingWriteFile:I/O Ring读写操作
7.2 调试命令
dt nt!_EPROCESS:查看EPROCESS结构dt nt!_SEGMENT_HEAP:查看段堆结构dt nt!_HEAP_SEG_CONTEXT:查看段后端上下文
8. 总结与趋势
Windows内核利用技术随着防御机制的增强而不断演进:
- 从直接的Token替换到复杂的池利用
- 从简单的堆溢出到幽灵块技术
- 从传统的池操作到I/O Ring等新机制利用
- 利用原语从任意读写发展为更精细的内存操作
未来内核利用可能会更多关注:
- 新引入的内核子系统
- 硬件特性与内核的交互
- 虚拟化环境下的内核行为
- 跨进程/跨会话的内核对象操作