Win32k内核漏洞分析与防御技术解析

本文深入分析MS08-025公告中的Win32k.sys内核漏洞,探讨ProbeForWrite/Read函数绕过机制、整数溢出利用原理及微软的修复策略,包含实际代码案例和防御方案。

MS08-025: Win32k漏洞分析

MS08-025修复了win32k.sys中的多个漏洞,攻击者可利用这些漏洞在内核模式下执行任意代码。这些漏洞仅支持本地利用,目前未发现远程攻击向量。

漏洞核心机制

其中一个漏洞涉及用户态内存指针的ProbeForWrite/Read检查绕过
ProbeForWrite/Read函数用于验证地址范围(基地址+长度)的以下属性(验证失败时抛出异常):

  • 范围位于用户态虚拟内存空间内
  • ProbeForWrite额外检查范围是否可写
    关键点:当长度参数为零时,这些函数不会抛出异常,而是继续正常流程(范围验证仍会执行)。

漏洞触发原理

通过向win32k发送特制用户态请求,可导致长度变量整数溢出,使其错误变为零值,从而绕过探测函数。例如:

1
2
3
4
5
6
// wParam为用户控制的DWORD值
str.MaximumLength = (ULONG)wParam;
if (!bAnsi) {
    str.MaximumLength *= sizeof(WCHAR); // 整数溢出可能导致MaximumLength=0
}
ProbeForWrite((PVOID)str.Buffer, str.MaximumLength, sizeof(BYTE)); // 零长度绕过检查

wParam=0x80000000时,乘法操作会导致溢出,使MaximumLength=0,进而绕过ProbeForWrite检查。后续操作可能向用户提供的指针(lParam)写入数据。

修复策略权衡

微软未选择直接修改探测函数(禁止零长度),因为会破坏大量现有接口。某些API需依赖零长度返回所需缓冲区大小(例如返回STATUS_BUFFER_TOO_SMALL并告知正确大小)。
最终方案是逐一检查可能引发整数溢出导致长度为零的探测点,确保安全性与兼容性平衡。

合法零长度用例示例

1
2
3
4
5
if (str.MaximumLength==0) {
    retval = STATUS_BUFFER_TOO_SMALL;
    *size_needed = sizeof(struct_to_copy_from);
    return retval;
}

此类设计允许通过零长度获取API调用所需实际大小。


本文内容基于安全漏洞研究与防御团队分析,原载于Microsoft Security Response Center博客。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计