MS08-066 : 捕获和修复ProbeForRead / ProbeForWrite绕过漏洞
afd.sys驱动程序负责处理套接字连接。MS08-066解决了afd.sys中的多个漏洞,这些漏洞可能允许攻击者在内核模式下执行任意代码。根据我们的调查,这些漏洞只能本地利用,不存在远程攻击向量。
其中一个漏洞涉及在使用用户提供的内存指针和长度时绕过ProbeForRead/ProbeForWrite检查。我们之前曾博客讨论过绕过这些函数的方法以及如何保护驱动程序免受此类漏洞影响。在那篇文章中,我们谈到攻击者通过使用零长度来绕过检查。本次更新涉及一种新型绕过方式:驱动程序未验证传入的整个范围。
让我们看一段源代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// 攻击者控制OutputBuffer和OutputBufferLength
void IOCTL_handler(...) {
[...]
try {
ProbeForWrite (OutputBuffer,
OutputBufferLength, // [1] 长度可能为零,即使使用内核模式地址也会被绕过
sizeof (UCHAR));
RtlCopyMemory(
OutputBuffer,
(PUCHAR)context+endpoint->Common.VcConnecting.RemoteSocketAddressOffset,
endpoint->Common.VcConnecting.RemoteSocketAddressLength // [2] 基于非零值复制到内核模式地址
);
} except( AFD_EXCEPTION_FILTER(&status) ) {
}
[...]
}
|
上述漏洞可能发生在驱动程序验证内存范围位于用户模式地址空间内,但随后使用不同范围进行复制时。在这种情况下,攻击者可以提供范围(addr=kernelmode, size=0)绕过ProbeForWrite检查(如[1]所示),但驱动程序随后会使用(addr=kernelmode,endpoint->Common.VcConnecting.RemoteSocketAddressLength)写入内核模式地址(如[2]所示)。
注重安全的内核开发人员可以通过验证OutputBufferLength并两次使用它来修复此问题:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
void IOCTL_handler(...) {
[...]
if (OutPutBufferLength!=endpoint->Common.VcConnecting.RemoteSocketAddressLength) {
// 退出...
return;
}
try {
ProbeForWrite (OutputBuffer,
OutputBufferLength,
sizeof (UCHAR));
RtlCopyMemory(
OutputBuffer,
(PUCHAR)context+endpoint->Common.VcConnecting.RemoteSocketAddressOffset,
OutPutBufferLength
);
} except( AFD_EXCEPTION_FILTER(&status) ) {
}
[...]
}
|
我们MSRC流程的一部分是寻找每个报告漏洞区域中的变体,并向工程组提供反馈,以便我们未来的代码不包含这些问题。在这种情况下,我们应用了三种并行策略:
- 对IOCTL处理程序进行模糊测试
- 在Phoenix之上应用二进制静态分析工具
- 对相关区域进行源代码审查
我们希望这篇博客文章能帮助您理解MS08-066,并让您了解在代码中需要注意什么。
- Fermin J. Serna, SVRD Blogger
文章按“原样”提供,不提供任何担保,也不授予任何权利。