新发现的EMF gdiplus.dll崩溃无法用于代码执行 | MSRC博客
昨日我们注意到一篇博客文章和安全焦点文章,提及Microsoft GDI+在解析特制EMF文件时可能存在新漏洞。您可能已听说此漏洞被称为"GpFont.SetData()"。我们希望就这个EMF解析错误的一些推测进行说明。
首先,我们的初步调查显示该漏洞无法用于代码执行。我们仍在研究触发此代码的所有潜在方式,但在目前所有常见情况下,我们的/GS缓解措施都是有效的深度防御手段。该EMF解析错误最终会向/GS安全cookie的低两位字节写入0x0000(单个Unicode 0字符)。只有这两个字节被覆盖,应用程序会因/GS失败而终止。
以下是问题发生的位置:
1
2
3
4
5
6
7
8
9
10
11
12
|
0:000> k
ChildEBP RetAddr
0007e37c 4ec9e783 gdiplus!GpFont::SetData+0x6a
0007e3a0 4ec9e70f gdiplus!MetafilePlayer::AddObject+0x8f
0007e3b4 4ec9d1b5 gdiplus!ObjectEPR::Play+0x1a
0007e3d0 4ec9ce34 gdiplus!GdipPlayMetafileRecordCallback+0x35
0007e3fc 4ec9cd4e gdiplus!MetafilePlayer::EnumerateEmfPlusRecords+0x66
0007e414 77f2072f gdiplus!EnumEmfWithDownLevel+0x52
0007e490 4ec9e625 gdiplus!MetafilePlayer::EnumerateEmfRecords+0xd7
0007edd4 4eca0c90 gdiplus!GpGraphics::EnumEmfPlusDual+0x27d
0007ee70 4ec9e67f gdiplus!GpMetafile::EnumerateForPlayback+0x686
0007ef90 4ed03350 gdiplus!GpMetafile::Play+0x26
|
gdiplus!GpFont::SetData代码显示存在明显的off-by-one错误。此问题在Vista发布前已修复。以下是Windows XP代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#define FamilyNameMax 32
…
WCHAR familyName[FamilyNameMax];
…
length = fontData->Length; // 来自EMF文件
…
if (length > FamilyNameMax)
{
length = FamilyNameMax;
}
…
// 读取familyName/data
UnicodeStringCopyCount (familyName, (WCHAR *)dataBuffer, length);
familyName[length]=0;
|
从汇编代码看:
1
2
3
4
5
6
7
8
9
|
gdiplus!GpFont::SetData:
4ecff9e9 8bff mov edi,edi
4ecff9eb 55 push ebp
4ecff9ec 8bec mov ebp,esp
4ecff9ee 83ec44 sub esp,44h
4ecff9f1 a10000dd4e mov eax,dword ptr [gdiplus!__security_cookie (4edd0000)] ds:0023:4edd0000=00006ea3
4ecff9f6 53 push ebx
4ecff9f7 8945fc mov dword ptr [ebp-4],eax // 安全cookie保存在ebp-4
4ecff9fa 8b4508 mov eax,dword ptr [ebp+8]
|
从函数开头可以看到安全cookie为00006ea3。继续往下看:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
4ecffa29 8b4804 mov ecx,dword ptr [eax+4]
4ecffa2c 894f10 mov dword ptr [edi+10h],ecx
4ecffa2f 8b4808 mov ecx,dword ptr [eax+8]
4ecffa32 894f18 mov dword ptr [edi+18h],ecx
4ecffa35 8b480c mov ecx,dword ptr [eax+0Ch]
4ecffa38 894f14 mov dword ptr [edi+14h],ecx
4ecffa3b 8b7014 mov esi,dword ptr [eax+14h]
4ecffa3e 8d4c3618 lea ecx,[esi+esi+18h]
4ecffa42 83c018 add eax,18h
4ecffa45 394d0c cmp dword ptr [ebp+0Ch],ecx
4ecffa48 0f8283000000 jb gdiplus!GpFont::SetData+0xe8 (4ecffad1)
4ecffa4e 83fe20 cmp esi,20h
4ecffa51 7603 jbe gdiplus!GpFont::SetData+0x6d (4ecffa56)
4ecffa53 6a20 push 20h
4ecffa55 5e pop esi
4ecffa56 56 push esi
4ecffa57 50 push eax
4ecffa58 8d45bc lea eax,[ebp-44h] // 0x20 WCHAR缓冲区
4ecffa5b 50 push eax
4ecffa5c e8d7750600 call gdiplus!GpRuntime::UnicodeStringCopyCount (4ed67038)
4ecffa61 a15009dd4e mov eax,dword ptr [gdiplus!Globals::FontCollection (4edd0950)]
4ecffa66 66895c75bc mov word ptr [ebp+esi*2-44h],bx
4ecffa6b 8b7008 mov esi,dword ptr [eax+8]
4ecffa6e 395e08 cmp dword ptr [esi+8],ebx
|
在字符串复制前中断,可以看到:
1
2
3
4
5
|
eax=00913658 ebx=00000000 ecx=00000020 edx=05aa010c esi=00000020 edi=0091c798
eip=4ecffa66 esp=0007e32c ebp=0007e37c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
gdiplus!GpFont::SetData+0x7d:
4ecffa66 66895c75bc mov word ptr [ebp+esi*2-44h],bx ss:0023:0007e378=6ea3
|
从上面的汇编代码可知安全cookie为00006ea3。mov指令执行前的内存状态:
1
2
3
4
5
6
7
8
9
|
0:000> dd ebp-0x10
0007e36c 44332211 001d0b0b 44332211 00006ea3
0007e37c 0007e3a0 4ec9e783 05aa00b4 00000024
0007e38c 0091e008 0091e008 00000030 0091e001
0007e39c 0091e008 0007e3b4 4ec9e70f 00000000
0007e3ac 05aa00b4 00000024 0007e3d0 4ec9d1b5
0007e3bc 0091e008 00004008 00000600 00000024
0007e3cc 05aa00a8 0007e3fc 4ec9ce34 00004008
0007e3dc 00000600 00000024 05aa00b4 0091e008
|
可以看到栈上的cookie保护着返回地址。复制操作后cookie被覆盖:
1
2
3
4
5
6
7
8
9
|
0:000> dd ebp-0x10
0007e36c 44332211 001d0b0b 44332211 00000000
0007e37c 0007e3a0 4ec9e783 05aa00b4 00000024
0007e38c 0091e008 0091e008 00000030 0091e001
0007e39c 0091e008 0007e3b4 4ec9e70f 00000000
0007e3ac 05aa00b4 00000024 0007e3d0 4ec9d1b5
0007e3bc 0091e008 00004008 00000600 00000024
0007e3cc 05aa00a8 0007e3fc 4ec9ce34 00004008
0007e3dc 00000600 00000024 05aa00b4 0091e008
|
我们一如既往地鼓励负责任地披露潜在漏洞。联系我们最佳方式是secure@microsoft.com。感谢。
- Jonathan Ness, MSRC工程团队
文章按"原样"提供,不提供任何担保,也不授予任何权利。