测试环境: 10.0.19045
漏洞出现在 CCommandBuffer::Initialize
函数中。由于分配的内存大小计算错误,导致发生溢出。补丁引入了一个关于可整除的快速检查,如果除法操作有余数,函数将终止,然而内存仍然会被分配 🙂
试图追踪漏洞函数的可达路径时,得到了如下结果。
从调用树来看,我们有三个选择:
-
CSurfaceBrush::GetBrushParameters
。 -
CPrimitiveGroup::GenerateDrawList
。 -
CPrimitiveGroup::GetTextureMemoryLayoutData
。
我选择了 CSurfaceBrush
来创建触发条件。
我创建了一个可执行 PoC 代码,它可以到达 CCommandBuffer::Initialize
代码。在创建过程中,我依赖于在 CSurfaceBrush::GetBrushParameters
函数上设置断点后获得的标准堆栈跟踪。为了创建这个 PoC,我使用了 HelloComposition
示例,从中可以看出如何构建资源树以到达漏洞代码。
这是 HelloComposition
用于在窗口中绘制随机大小且填充随机颜色的精灵时创建的资源树:
分析了上述树和示例代码后,可以清楚地知道达到漏洞代码需要满足的条件:
-
由于需要运行渲染器,因此需要一个窗口。 -
渲染发生的区域必须可见。 -
通过 NtUserCreateDCompositionHwndTarget
获取 [[Composition Window]] 的句柄。 -
在 [[Composition Window]] 上以 CVisualTargetMarshaler
打开句柄。
下面你可以看到满足上述条件并触发漏洞的资源树。
在下面的图片中,你可以看到溢出是如何发生的:
-
内存分配。RCX 寄存器包含 0x90,这是分配的内存大小。 -
RAX 包含指向分配内存的指针。 -
memcpy 前的状态。RCX 包含目标缓冲区的地址(在前面步骤中分配),RDX 包含源缓冲区的地址,R8 包含要复制的数据大小。可以看到 0x90 < 0x95。
原文始发于微信公众号(3072):CVE-2024-30051 dwmcore 堆溢出漏洞分析