文章总结: CheckPointResearch在Windows的GraphicsDeviceInterface(GDI)中发现了三个安全漏洞CVE-2025-30388、CVE-2025-53766和CVE-2025-47984,分别评级为重要、严重和重要。这些漏洞可能导致远程代码执行、内存泄露和信息泄露,且已被微软在2025年5月、7月和8月的星期二补丁中修复。文章详细分析了这些漏洞的技术细节、触发条件和修复方式,特别是CVE-2025-30388和CVE-2025-53766可被远程利用,无需用户交互,对解析特制图元文件的Web服务构成高风险威胁。建议Windows用户及时安装安全补丁以防范潜在风险。
综合评分: 85
文章分类: 漏洞分析,漏洞预警,应用安全,网络安全,二进制安全
Windows 图形漏洞导致远程代码执行与内存泄露
白帽子左一
白帽子左一
2025年11月26日 12:01
江西
扫码领资料
获网安教程
来Track安全社区投稿~
赢千元稿费!还有保底奖励~(https://bbs.zkaq.cn)
背景
Check Point Research(CPR)在 Windows 的 Graphics Device Interface(GDI) 中发现了三个安全漏洞。我们已及时将这些问题报告给微软,并分别在 2025 年 5 月、7 月和 8 月的 星期二补丁 更新中得到修复。
这些漏洞包括:
- • CVE-2025-30388,评级为重要,且被认为更可能被利用;
- • CVE-2025-53766,被归类为严重漏洞,可能允许远程攻击者在受影响系统上执行任意代码;
- • CVE-2025-47984,同样评级为重要,可能导致通过网络未经授权泄露敏感信息。
此类漏洞披露突显了采取主动措施减轻潜在风险的必要性。我们在修复补丁发布后撰写此博客的目的,是进一步提高对这些漏洞的认识,并为 Windows 用户提供防御性洞察与缓解建议。在接下来的章节中,我们将详细介绍我们针对 Windows GDI 使用 EMF 格式开展的模糊测试活动,该活动促成了这些安全漏洞的发现。
幾何体失控——CVE-2025-30388
我们发现了三个与处理 EmfPlusDrawString、EmfPlusFillRects 和 EmfPlusFillClosedCurve 记录相关的独立崩溃案例。这三种情况具有相同的根本原因:另一个记录为利用创造了条件。然而,最终结果取决于执行过程中处理的其他记录。我们当前的分析重点是涉及 EmfPlusDrawString 记录的崩溃。
在 GdiPlus.dll 模块的版本 10.0.26100.3037 中的 ScanOperation::AlphaMultiply_sRGB()、ScanOperation::Blend_sRGB_sRGB_MMX() 和 EpAntialiasedFiller::OutputSpan() 函数内,发生了多次访问冲突异常。这些异常是在系统尝试读写一个大小为 4000/0xFA0 字节的堆块末尾,或尝试访问已保留但未分配的内存时触发的。
该漏洞可能允许远程攻击者通过特制的 EMF+ 图元文件执行越界读写内存操作。图 1 展示了 ScanOperation::AlphaMultiply_sRGB() 函数在崩溃时的反编译源代码。
在我们用于复现漏洞的崩溃样本(PoC)中,一个 EmfPlusClear 记录位于该图元文件的 EmfPlusDrawString 记录之前。该记录会清空输出坐标空间,并根据其 Color 字段设置背景颜色与透明度。该字段包含一个 EmfPlusARGB 对象,指定了红、绿、蓝与透明度分量。此细节至关重要,因为它允许攻击者在利用过程中控制写入内存的数值。列表 1 展示了受影响的 EmfPlusClear 记录。
EmfPlusClear clear = {
.Type = 0x4009,
.Flags = 0x0102,
.Size = 0x0000003c,
.DataSize = 0x00000030,
.Color = 0xaabbccff // Value written to memory
};
进一步调查发现,EmfPlusClear 记录处理程序使用 EpScanBitmap::Start() 函数分配了一个 4000 字节(0xFA0)的堆块。该缓冲区随后被填充为指定的 EmfPlusARGB 对象,在处理 EmfPlusDrawString 记录时,会由 AlphaMultiply_sRGB() 函数对其进行 Alpha 通道乘法运算。
注意,存储在 ebx 寄存器中的循环计数器从 0x950 开始。由于每次迭代会向目标缓冲区 ecx + edx 写入一个 4 字节的对象,当计数器达到 0x567 时,函数便会在超过 1000 字节处发生越界写入。这一行为可在 列表 2 的崩溃分析片段中看到。
0:000> g
(16b8.5ec): Access violation - code c0000005 (first/second chance not available)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=ffccbbaa ebx=00000567 ecx=022cec8c edx=08732374 esi=000015e3 edi=db000000
eip=74e16d9d esp=0075ddb0 ebp=0075ddc0 iopl=0 nv up ei ng nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000282
gdiplus!ScanOperation::AlphaMultiply_sRGB+0x2d:
74e16d9d 890411 mov dword ptr [ecx+edx],eax ds:002b:0aa01000=????????
0:000> kb
# ChildEBP RetAddr Args to Child
00 0075ddc0 74e16653 00000950 0872bd0c 0075e99c gdiplus!ScanOperation::AlphaMultiply_sRGB+0x2d
01 0075ddf4 74e16520 00000000 00000000 00000015 gdiplus!EpScanBitmap::NextBuffer+0xc3
02 0075de2c 74e15c91 00000000 00000000 00000015 gdiplus!DpOutputSolidColorSpan::OutputSpan+0x40
03 0075de58 74e188d4 00000000 ffffff19 00000955 gdiplus!DpClipRegion::OutputSpan+0x141
04 0075de7c 74e15988 00000000 0f47eed0 74e01b40 gdiplus!EpAliasedFiller::FillEdgesWinding+0x54
05 0075e938 74e0420e 00000001 00000003 00000000 gdiplus!RasterizePath+0x5d8
06 0075ea74 74e01cee 08747da0 0873cf98 0075eab8 gdiplus!DpDriver::StrokePath+0x3ee
07 0075ea9c 74e01db7 0075eab8 0075eb20 0075ede0 gdiplus!GpGraphics::DrvStrokePath+0x38
08 0075eadc 74df3b06 0075eb10 0075eb20 0075edcc gdiplus!GpGraphics::RenderDrawPath+0xbc
09 0075ed68 74e50a58 0075edcc 0075ed98 00000002 gdiplus!GpGraphics::DrawLines+0x148
0a 0075ee54 74f034c2 0aa08ff0 0f2a2fb8 00000000 gdiplus!FullTextImager::GdipLscbkDrawUnderline+0x228
0b 0075eee4 74ef7d57 0075f048 00000004 00000000 gdiplus!DrawUnderlineMerge+0x16f
0c 0075ef90 74eef9fd 00000001 00000000 00001015 gdiplus!DisplaySublineCore+0x25b
0d 0075f018 74ed907c 0aa40fa0 0aa40fa0 0aa40fa0 gdiplus!LsDisplayLine+0x193
0e 0075f02c 74edc08e 0075f048 00000000 0aa04e70 gdiplus!BuiltLine::Draw+0x12
0f 0075f058 74edbfd4 0aa40fa0 00000000 0aa04e70 gdiplus!FullTextImager::RenderLine+0x50
10 0075f0d8 74ed915f 0aa04e70 74ed9090 00000000 gdiplus!FullTextImager::Render+0x211
11 0075f108 74e6192a 0873ed28 0075f150 08744cb0 gdiplus!FullTextImager::Draw+0xcf
12 0075f3c8 74e8c55f 05b70184 00000014 0874bfe0 gdiplus!GpGraphics::DrawString+0x2f412
13 0075f404 74e02081 08744cb0 0000401c 0000df00 gdiplus!DrawStringEPR::Play+0xdf // Affects EmfPlusDrawString record
14 0075f428 74e01f97 0000401c 0000df00 00000044 gdiplus!GdipPlayMetafileRecordCallback+0x71
15 0075f45c 74e01e7c 00000104 05b700a8 0865ad58 gdiplus!MetafilePlayer::EnumerateEmfPlusRecords+0x97
16 0075f47c 75ca5d2f a901095a 0866cff8 05b70098 gdiplus!EnumEmfWithDownLevel+0x8c
17 0075f510 75ca4309 74e01df0 08744cb0 0075f58c gdi32full!bInternalPlayEMF+0x830
18 0075f524 771cad7f a901095a 824606f7 74e01df0 gdi32full!EnumEnhMetaFile+0x39
19 0075f544 74df5ed6 a901095a 824606f7 74e01df0 GDI32!EnumEnhMetaFileStub+0x2f
1a 0075f5a0 74df5b3b a901095a 824606f7 0075f5e4 gdiplus!MetafilePlayer::EnumerateEmfRecords+0xdf
1b 0075f648 74df81bc 08744cb0 824606f7 0075f774 gdiplus!GpGraphics::EnumEmfPlusDual+0x351 // Affects EMF+ Dual
1c 0075f7b8 74e1384c 0075f810 0075f810 00000002 gdiplus!GpMetafile::EnumerateForPlayback+0x819
1d 0075f8d8 74e01903 08723f28 0075f908 0075f918 gdiplus!GpGraphics::DrawImage+0x5ec
1e 0075f944 74e8a69e 08723f28 0075f96c 0075f97c gdiplus!GpGraphics::DrawImage+0x61
1f 0075f9a4 74e8b8a6 00000064 00000064 08723f28 gdiplus!GpMetafile::GetBitmap+0x1d2
20 0075f9b8 74e6e16b 00000064 00000064 00000000 gdiplus!GpMetafile::GetThumbnail+0x26
21 0075f9e0 006511a0 08723f28 00000064 00000064 gdiplus!GdipGetImageThumbnail+0x6b // Reachable via thumbnails
<<<<<<<<<<<<<<unnecessary information removed>>>>>>>>>>>>>>
0:000> dd [ecx+edx]-0xfa0-10 L8
0aa00050 00000000 00000000 046e0b3c dcbabbbb
0aa00060 ffccbbaa ffccbbaa ffccbbaa ffccbbaa
0:000> dd [ecx+edx]-10 L8
0aa00ff0 ffccbbaa ffccbbaa ffccbbaa ffccbbaa
0aa01000 ???????? ???????? ???????? ????????
Alpha 值会与颜色值相乘,以确保透明区域(alpha 值为 0 的地方)不会产生任何颜色贡献(R = G = B = 0)。因此,在半透明区域中,颜色看起来会更暗,因为与不透明对象相比,这些对象发出的光更少。
第四个字节是 alpha 值,其范围从 0x00 到 0xFF。将 alpha 值设置为 0xFF 能让攻击者几乎完全控制写入缓冲区的内容,因为 RGB 值保持不变。在上面的示例中,B=0xAA、G=0xBB、R=0xCC 和 A=0xFF 被写入了目标缓冲区。
如 图 2 所示,补丁分析确认,在处理多个图元文件记录时发生的崩溃都具有共同的根本原因:在导致崩溃的其他记录之前存在包含无效 RECT 对象的 EmfPlusSetTSClip 记录。列表 3 展示了我们崩溃样本中受影响的记录。
EmfPlusSetTSClip clip = {
.Type = 0x403a,
.Flags = 0x0003, // Number of RECT objects
.Size = 0x00000048,
.DataSize = 0x0000003c,
.NumRects[3] = {
{ 0x00000005, 0x00000000, 0x04000000, 0x0000001f }, // Valid
{ 0x00000000, 0x00e90000, 0xfff70000, 0x00000000 }, // Not valid
{ 0x00000000, 0x00000000, 0x00000015, 0x003f8000 } // Valid
}
};
处理无效的 RECT 对象会导致基于堆的缓冲区溢出,攻击者可借此执行越界内存操作。攻击者可以通过使用其他各种图元文件记录来读取或写入内存,因为被破坏的 EmfPlusSetTSClip 记录为利用奠定了基础。从 图 3 中对样例 EmfPlusFillRects 记录的渲染结果可以看出,可以通过填充矩形泄露未初始化或已初始化的堆字节。
从 Microsoft Word 365 的渲染图像可以看到,输出在每次渲染中都不同,这表明该崩溃样本泄露了内存,并最终导致 Word 意外终止。这种行为已经跨越了安全边界,因为如果攻击者能读取渲染后的图像,例如通过 Web 浏览器中的 JavaScript,这将导致信息泄露。
微软在 GdiPlus.dll 版本 10.0.26100.4061 中,通过在 SetTSClipEPR::Play() 处理函数中引入 ValidateAndSet() 和 IsRectValid() 函数来验证 RECT 对象,从而修复了此漏洞,如 图 4 所示。
该问题在 2025 年 5 月 星期二补丁 的 KB5058411 中得到解决,被作为重要级别的远程代码执行漏洞处理,编号为 CVE-2025-30388。值得注意的是,该漏洞也影响 Mac 与 Android 版的 Microsoft Office。此外,MSRC 的可利用性评估为“更可能被利用”,表明这是一个对攻击者而言高价值的目标。
负空间 —— CVE-2025-53766
在处理 EmfPlusDrawRects 记录时,我们发现了第四次崩溃。在 GdiPlus.dll 版本 10.0.26100.4202 中的 ScanOperation::AlphaDivide_sRGB() 函数发生了访问冲突异常,因为该函数试图写入已保留但未分配的内存。
此漏洞可能允许远程攻击者通过特制的 EMF+ 图元文件执行越界写入操作。图 5 展示了崩溃时该函数的反编译源代码。
此问题与前面提到的 CVE-2025-30388 类似。此前的漏洞是由于在导致崩溃的记录之前存在包含无效 RECT 对象的 EmfPlusSetTSClip 记录导致的。在本例中,漏洞源于受影响的 EmfPlusDrawRects 记录中的一系列 EmfPlusRect 对象,详见 列表 4。
EmfPlusDrawRects rects = {
.Type = 0x400B,
.Flags = 0xEF00,
.Size = 0x00000048,
.DataSize = 0x0000003C,
.Count = 0x00000003,
.RectData[Count] = {
{ 0x0000, 0x3400, 0x3434, 0x3434 },
{ 0x3434, 0x3434, 0x3434, 0x3434 },
{ 0x3434, 0x3434, 0x3434, 0x3434 },
{ 0x3434, 0x3434, 0x0000, 0x3000 },
{ 0x3434, 0x3434, 0x3434, 0x3434 },
{ 0x3434, 0x3434, 0x0034, 0x0010 },
{ 0x4000, 0x3434, 0x3434, 0x3434 },
}
};
EmfPlusDrawRects 记录之前存在一个用于图形操作的 EmfPlusPen 对象,该对象由一个 EmfPlusObject 记录指定。EmfPlusPen 对象定义了与画笔关联的图形画刷。该画刷为纯色画刷,由一个 EmfPlusARGB 值表示。写入操作中 eax 寄存器的来源可由攻击者通过该值控制,如 列表 5 的崩溃分析片段所示。
0:000> g
(abc.7148): Access violation - code c0000005 (first/second chance not available)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=ffff004c ebx=000000ff ecx=fffcf63c edx=086cb9c4 esi=6af57480 edi=0868bd58
eip=6af574b3 esp=004feb34 ebp=004feb48 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
gdiplus!ScanOperation::AlphaDivide_sRGB+0x33:
6af574b3 890411 mov dword ptr [ecx+edx],eax ds:002b:0869b000=10000011
0:000> kb
# ChildEBP RetAddr Args to Child
00 004feb48 6af573bd 00000035 0868bd0c 004fef98 gdiplus!ScanOperation::AlphaDivide_sRGB+0x33
01 004feb7c 6af5b364 00000064 00000063 00000064 gdiplus!EpScanBitmap::NextBuffer+0xdd
02 004febbc 6af5ab8e 004fef98 004fee40 00000001 gdiplus!OnePixelLineDDAAliased::DrawXMajor+0x54
03 004fecd4 6af5aabf 004fef98 00000000 00000000 gdiplus!DrawSolidLineOnePixelAliased+0x9e
04 004fed18 6af58bb8 004fefac 004fee20 00000005 gdiplus!DrawSolidStrokeOnePixel+0x9f
05 004fef48 6af3fe26 00000000 00000000 6af5aa20 gdiplus!FixedPointPathEnumerate+0x358
06 004feff8 6af405ac 086a7da0 0869cf98 004ff178 gdiplus!DpDriver::SolidStrokePathOnePixel+0x124
07 004ff134 6af43107 086a7da0 0869cf98 004ff178 gdiplus!DpDriver::StrokePath+0x33c
08 004ff15c 6af43096 004ff178 004ff1e8 086b1f8c gdiplus!GpGraphics::DrvStrokePath+0x3b
09 004ff19c 6af429c7 004ff1c4 004ff1e8 086b1f78 gdiplus!GpGraphics::RenderDrawPath+0xbc
0a 004ff39c 6afd3746 086b1f78 07bb0160 00000003 gdiplus!GpGraphics::DrawRects+0x356
0b 004ff3c4 6af40b59 086a4cb0 0000400b 00000400 gdiplus!DrawRectsEPR::Play+0x86
0c 004ff3e8 6af40a67 0000400b 00000400 0000003c gdiplus!GdipPlayMetafileRecordCallback+0x79
0d 004ff41c 6af4094c 00000104 07bb00a8 08006d58 gdiplus!MetafilePlayer::EnumerateEmfPlusRecords+0x97
0e 004ff43c 75eab76f 1c01154a 08d06ff8 07bb0098 gdiplus!EnumEmfWithDownLevel+0x8c
0f 004ff4d0 75ea9d49 6af408c0 086a4cb0 004ff54c gdi32full!bInternalPlayEMF+0x830
10 004ff4e4 75f2b9bf 1c01154a a94624e7 6af408c0 gdi32full!EnumEnhMetaFile+0x39
11 004ff504 6af368f6 1c01154a a94624e7 6af408c0 GDI32!EnumEnhMetaFileStub+0x2f
12 004ff560 6af36551 1c01154a a94624e7 004ff5a4 gdiplus!MetafilePlayer::EnumerateEmfRecords+0xdf
13 004ff608 6af38bdc 086a4cb0 a94624e7 004ff734 gdiplus!GpGraphics::EnumEmfPlusDual+0x351
14 004ff778 6af5454c 004ff7d0 004ff7d0 00000002 gdiplus!GpMetafile::EnumerateForPlayback+0x819
15 004ff898 6af467ac 08683f28 004ff8c8 004ff8d8 gdiplus!GpGraphics::DrawImage+0x5ec
16 004ff904 6afd198e 08683f28 004ff92c 004ff93c gdiplus!GpGraphics::DrawImage+0x61
17 004ff964 6afd2b96 00000064 00000064 08683f28 gdiplus!GpMetafile::GetBitmap+0x1d2
18 004ff978 6afb540b 00000064 00000064 00000000 gdiplus!GpMetafile::GetThumbnail+0x26
19 004ff9a0 009a11a0 08683f28 00000064 00000064 gdiplus!GdipGetImageThumbnail+0x6b
<<<<<<<<<<<<<<unnecessary information removed>>>>>>>>>>>>>>
在位图图像中,扫描线是指一条水平像素行。逐行处理图像意味着一次处理一条扫描线,从左到右、从上到下。进一步分析表明,EpScanBitmap::NextBuffer() 函数从未验证即将处理的扫描线数量是否适配目标位图,这意味着如果一次调用请求的扫描线数量超过实际存在的数量,该函数可能会被诱导读取或写入位图底部边界之外的位置。
假设用于缩略图生成的位图分配为 100×100(0x64 × 0x64)像素,那么 PoC 图元文件中的矩形数据会故意将扫描位置推到位图底部之外,从而触发越界写入。这些矩形中的任意一个都会迫使光栅化器(将矢量图形转换为像素网格的组件)处理超过位图 0–99 范围的 Y 坐标的扫描线。
微软在 GdiPlus.dll 版本 10.0.26100.4946 中修复了此漏洞,通过在 EpScanBitmap::NextBuffer() 函数中增加检查,以检测请求的扫描线数量是否超过位图高度,如 图 6 所示。该函数现在会自动裁剪请求的扫描线,使其保持在剩余行数范围内,从而避免任何越界访问,如 图 7 所示。
此漏洞在 2025 年 8 月 星期二补丁 的 KB5063878 中得到解决,作为一个严重级别的远程代码执行漏洞进行跟踪,编号为 CVE-2025-53766。值得注意的是,该漏洞不需要任何权限或用户交互,可通过网络进行远程利用,因此对解析特制图元文件的 Web 服务构成高风险威胁。
未完事项 —— CVE-2025-48984
在处理 EMR_STARTDOC 记录时,我们发现了第五次崩溃,该问题看起来与 CVE-2022-35837 漏洞相关。在 gdi32full.dll 版本 10.0.26100.3624 中的 StringLengthWorkerW() 函数发生了访问冲突异常,这是在尝试读取一个大小为 288/0x120 字节的堆块的末尾时触发的。列表 6 包含了相关的崩溃分析片段。
0:000> g
(48b0.7b68): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00dbf028 ebx=08195f7c ecx=08196000 edx=7fffffbc esi=7ffffffe edi=00000000
eip=7792d586 esp=00dbf014 ebp=00dbf01c iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202
gdi32full!StringLengthWorkerW+0xf:
7792d586 663939 cmp word ptr [ecx],di ds:002b:08196000=????
0:000> kb
# ChildEBP RetAddr Args to Child
00 00d3f37c 7796f55c 00d3f388 00000000 00d3f3cc gdi32full!StringLengthWorkerW+0xf
01 00d3f38c 77974155 00d3f3b0 0885bf4c 779740b0 gdi32full!StringCbLengthW+0x1a
02 00d3f3cc 77966ffb 9e011903 0885dff8 00000001 gdi32full!MRSTARTDOC::bPlay+0xa5
03 00d3f420 6d971f4d 9e011903 0885dff8 0885bf4c gdi32full!PlayEnhMetaFileRecord+0x5b
04 00d3f438 6d971e21 08ab5720 6d971c40 0000006b gdiplus!EmfEnumState::PlayRecord+0x2d
05 00d3f450 6d980b8c 0000006b 00000024 0885bf54 gdiplus!EmfEnumState::ProcessRecord+0x1e1
06 00d3f470 6d9b939d 0000006b 00000000 00000024 gdiplus!GdipPlayMetafileRecordCallback+0xec
07 00d3f49c 7796824f 9e011903 0885dff8 0885bf4c gdiplus!EnumEmfDownLevel+0x7d
08 00d3f530 77966829 6d9b9320 08ab2cb0 00d3f5ac gdi32full!bInternalPlayEMF+0x830
09 00d3f544 7632ad7f 9e011903 65461856 6d9b9320 gdi32full!EnumEnhMetaFile+0x39
0a 00d3f564 6d9768c6 9e011903 65461856 6d9b9320 GDI32!EnumEnhMetaFileStub+0x2f
0b 00d3f5c0 6d9741ac 9e011903 65461856 00d3f664 gdiplus!MetafilePlayer::EnumerateEmfRecords+0xdf
0c 00d3f678 6d9789eb 08ab2cb0 65461856 00d3f7b4 gdiplus!GpGraphics::EnumEmf+0x413
0d 00d3f7f8 6d99452c 00d3f850 00d3f850 00000002 gdiplus!GpMetafile::EnumerateForPlayback+0x658
0e 00d3f918 6d98676c 08a93f28 00d3f948 00d3f958 gdiplus!GpGraphics::DrawImage+0x5ec
0f 00d3f984 6da108fe 08a93f28 00d3f9ac 00d3f9bc gdiplus!GpGraphics::DrawImage+0x61
10 00d3f9e4 6da11b06 00000064 00000064 08a93f28 gdiplus!GpMetafile::GetBitmap+0x1d2
11 00d3f9f8 6d9f439b 00000064 00000064 00000000 gdiplus!GpMetafile::GetThumbnail+0x26
12 00d3fa20 00db11aa 08a93f28 00000064 00000064 gdiplus!GdipGetImageThumbnail+0x6b
<<<<<<<<<<<<<<unnecessary information removed>>>>>>>>>>>>>>
堆栈跟踪表明问题可能出现在 StringLengthWorkerW() 函数,该函数对用户控制的数据执行长度检查,并假设输入为以空字符结尾的字符串。然而,如果提供的字符串不是以空字符结束,该函数可能会读取超出已分配缓冲区之外的内容,导致潜在的信息泄露。
图 8 中 MRSTARTDOC::bPlay() 函数的反编译源代码表明,CVE-2022-35837 通过在其字段非空时使用存储在变量 v5 中的计算偏移量为 lpszDocName 和 lpszOutput 字段赋值的方式得到了修复。
列表 7 展示了受影响的 EMR_STARTDOC 图元文件记录。DOCINFO 结构包含输入与输出文件名及其他由 StartDoc() 函数使用的信息,该函数用于启动打印作业。
EMR_STARTDOC startDoc = {
.Type = 0x0000006b,
.Size = 0x0000002c,
.docInfo = {
.cbSize = 0x00000020,
.lpszDocName = 0x2b464d45, // -> 0x1002
.lpszOutput = 0x00004001, // -> 0x6b14
.lpszDatatype = 0x0000001c,
.fwType = 0x00000010
}
};
列表 8 中显示的原始 EMR_STARTDOC 记录表明,在修补了最初报告的任意信息泄露之后,lpszDocName 字段指向 0x1002,位于记录之后、偏移 1Ch 的位置。同时,lpszOutput 字段指向 0x6b14,位于偏移 1Ch + 14h = 30h:
0000h 6B 00 00 00 2C 00 00 00 20 00 00 00 45 4D 46 2B k...,... ...EMF+
0010h 01 40 00 00 1C 00 00 00 10 00 00 00 02 10 C0 DB .@............ÀÛ
0020h 01 00 00 05 05 7F FF 00 60 00 00 00 46 00 00 00 .....ÿ.`...F...
0030h 14 6B 6B 6B 6B 6B 6B 6B 6B 6B 6B 6B 6B 6B 5C 6B .kkkkkkkkkkkkk\k
0040h 6B 6B 6B 6B 6B 6B 6B 6B 6B 10 6B 6B 6B 6B 6B 6B kkkkkkkkk.kkkkkk
0050h 6B 6B 6B 6B kkkk
越界读取发生的原因是 MRSTARTDOC::bPlay() 函数会验证记录内部的字符串偏移。一个特制的图元文件可能会在 lpszDocName 字段的第一个字符串中填充数据,使其几乎到达记录末尾。在复制该字符串之后,代码会将其内部游标推进到该点之后,但对 lpszOutput 字段进行的下一次验证仍然将提供的偏移视为相对于记录原始基址。
这种不一致使攻击者能够提供一个通过 MR::bValidOff() 函数检查、但实际上指向堆块之外的值。由于未找到空终止符,StringLengthWorkerW() 函数会继续读取相邻内存,从而暴露其内容。漏洞触发样例通过将 EMF_HEADER.nBytes 字段设置为仅 0x120(288)字节,进一步加剧了问题,使得分配的缓冲区比嵌入的数据更小,并保证会发生越界读取。
微软在 gdi32full.dll 的版本 10.0.26100.4652 中,通过修正偏移运算修复了 MRSTARTDOC::bPlay() 处理函数中的此漏洞。修补后的函数现在会在重新验证之前,将指针转换回相对于记录起始位置的偏移,并对 lpszOutput 字段应用相同的逻辑。因此,该检查与实际将要解引用的数据一致,如 图 9 所示。
此漏洞通过 2025 年 7 月补丁星期二 中的 KB5062553 得到修复,被作为重要级别的信息泄露漏洞并以 CVE-2025-47984 进行追踪。MSRC 将其归类为 CWE-693:保护机制失效,在这种情况下实际上意味着针对 CVE-2022-35837 的安全修复并不完整。
获取更多精彩内容,尽在Track安全社区~:https://bbs.zkaq.cn
声明:⽂中所涉及的技术、思路和⼯具仅供以安全为⽬的的学习交流使⽤,任何⼈不得将其⽤于⾮法⽤途以及盈利等⽬的,否则后果⾃⾏承担。所有渗透都需获取授权!
@
学习更多渗透技能!体验靶场实战练习

(hack视频资料及工具)
往期推荐
看到这里了,来个一键三连(点赞+收藏+关注)吧
~
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:白帽子左一 白帽子左一《Windows 图形漏洞导致远程代码执行与内存泄露》