漏洞名称:Microsoft Windows图形渲染引擎WMF格式解码内存越界漏洞
发现者:cocoruder(frankruder_at_hotmail.com) http://ruder.cdut.net
类型:设计错误
最后更新时间:07/01/2006
受威胁的系统:
Microsoft Windows XP SP2
Microsoft Windows XP SP1
Microsoft Windows Server 2003 SP1
Microsoft Windows Server 2003
Microsoft Windows ME
Microsoft Windows 98se
Microsoft Windows 98
Microsoft Windows 2000SP4
未受威胁的系统:
目前未知
厂商:
www.microsoft.com漏洞描述:
Microsoft Windows的WMF图形渲染引擎处理特殊格式的wmf文件时缺乏参数检查,存在多个内存越界漏洞,如果用户访问了恶意的WMF格式文件将导致拒绝服务攻击。
注意此文章中涉及的问题与ms06-001以及ms05-053中描述的无关。事实上,这是我在测试ms06-001时偶然发现的。
技术细节:
当前发现至少有2个地方可以触发内存越界错误。
1.ExtCreateRegion调用导致内存越界。
函数原型:
HRGN ExtCreateRegion(
CONST XFORM *lpXform, // transformation data
DWORD nCount, // size of region data
CONST RGNDATA *lpRgnData // region data buffer
);
PlayMetaFileRecord函数在调用此函数前会组织RGNDATA *lpRgnData参数,涉及下面几个结构
WMFRECORD结构:
typedef struct _StandardMetaRecord
{
DWORD Size; /* Total size of the record in WORDs */
WORD Function; /* Function number (defined in WINDOWS.H) */
WORD Parameters[]; /* Parameter values passed to function */
} WMFRECORD;
ExtCreateRegion调用对应的Parameters结构:
typedef struct _Parameters
{
char unknow1[0x0a];
WORD All_PointtStruct_Num; //后面PointtStruct块的总数
char unknow2[0x0a];
char PointtStruct[]; //首块
}Parameters;
一个PointtStruct块的结构:
typedef struct _PointtStruct
{
WORD PointNum; //后面的RECT结构成员的数目(1个成员2字节)
WORD Point[PointNum]; //4个Point构成1个RECT
char unkonow[6];
}PointtStruct;
因此每个PointtStruct块的总字节数=PointNum*2+8
ExtCreateRegion调用码为0xff,下面的代码完成计算并分配堆内存操作。
.text:7F00FE07 loc_7F00FE07: ; CODE XREF: PlayMetaFileRecord+1256j
.text:7F00FE07 sub eax, 3
.text:7F00FE0A jnz loc_7F022B9A ; 0xff
.text:7F00FE10 movzx ecx, word ptr [ebx+10h] ;取得PointtStruct块总数
.text:7F00FE14 mov [ebp-88h], ecx ;保存
.text:7F00FE1A test ecx, ecx
.text:7F00FE1C jnz short loc_7F00FE2E ;跳
.text:7F00FE1E xor eax, eax
.text:7F00FE20 push eax ; int
.text:7F00FE21 push eax ; int
.text:7F00FE22 push eax ; int
.text:7F00FE23 push eax ; int
.text:7F00FE24 call CreateRectRgn
.text:7F00FE29 jmp loc_7F010494
.text:7F00FE2E ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
.text:7F00FE2E
.text:7F00FE2E loc_7F00FE2E: ; CODE XREF: PlayMetaFileRecord+C15j
.text:7F00FE2E xor edi, edi
.text:7F00FE30 mov [ebp-8Ch], edi
.text:7F00FE36 lea eax, [ebx+1Ch] ;得到首PointtStruct块地址
.text:7F00FE39 mov [ebp-90h], eax ;保存
.text:7F00FE3F and [ebp-94h], edi
.text:7F00FE45 and [ebp-98h], edi
.text:7F00FE4B test ecx, ecx
.text:7F00FE4D jbe short loc_7F00FE8C
.text:7F00FE4F
.text:7F00FE4F loc_7F00FE4F: ; CODE XREF: PlayMetaFileRecord+C83j
.text:7F00FE4F movzx ecx, word ptr [eax] ;取得PointNum,可触发内存错误**
.text:7F00FE52 mov edx, ecx
.text:7F00FE54 shr edx, 1 ;PointNum/2
.text:7F00FE56 add edx, edi ;累加PointNum/2
.text:7F00FE58 cmp edx, edi
.text:7F00FE5A jb loc_7F0106D5
.text:7F00FE60 mov edi, edx
.text:7F00FE62 mov [ebp-8Ch], edi
.text:7F00FE68 cmp ecx, 7FFFFFFBh
.text:7F00FE6E jnb loc_7F0106D5
.text:7F00FE74 lea eax, [eax+ecx*2+8]
.text:7F00FE78 inc dword ptr [ebp-98h] ;计数器+1
.text:7F00FE7E mov ecx, [ebp-98h]
.text:7F00FE84 cmp ecx, [ebp-88h] ;与PointtStruct块总数相比较
.text:7F00FE8A jb short loc_7F00FE4F ;遍历所有PointtStruct块结构
.text:7F00FE8C
.text:7F00FE8C loc_7F00FE8C: ; CODE XREF: PlayMetaFileRecord+C46j
.text:7F00FE8C ; PlayMetaFileRecord+14D8j
.text:7F00FE8C cmp dword ptr [ebp-94h], 0
.text:7F00FE93 jnz loc_7F022BA2
.text:7F00FE99 cmp edi, 0FFFFFFDh
.text:7F00FE9F jnb loc_7F022BA2
.text:7F00FEA5 mov eax, [ebp-8Ch]
.text:7F00FEAB add eax, 2
.text:7F00FEAE shl eax, 4
.text:7F00FEB1 mov [ebp-9Ch], eax
.text:7F00FEB7 push eax ; uBytes
.text:7F00FEB8 push 0 ; uFlags
.text:7F00FEBA call ds:LocalAlloc ;正常的话在这里分配堆内存
.text:7F00FEC0 mov edi, eax
因此当设置足够大的All_PointtStruct_Num,PointNum,但后面未有足够多的PointtStruct结构,在遍历所有PointNum时即会产生内存越界,导致拒绝服务攻击。
一个例子:
...05020000FF0044444444444444444444FFFF33333333333333333333FFFF41424344...
2.ExtEscape POSTSCRIPT_INJECTION调用导致内存越界。
原型:
int ExtEscape(
hdc, // handle to DC (HDC)
POSTSCRIPT_INJECTION, // nEscape param of ExtEscape
cbInput, // size of input buffer
lpszInData, // pointer to input (PSINJECTDATA *)
0, // cbOutput param of ExtEscape
NULL // lpszOutData param of ExtEscape
);
cbInput我们可以控制,如果设置足够大的cbInput,但后面未有足够多的szInData的话,将可能产生内存越界,导致拒绝服务攻击。
ExtEscape里处理POSTSCRIPT_INJECTION(0x1016)调用的代码如下:
.text:7F027312 loc_7F027312: ; CODE XREF: ExtEscape+11Ej
.text:7F027312 ; ExtEscape+12Aj
.text:7F027312 test byte ptr [ecx+4], 40h
.text:7F027316 jnz loc_7F017CEC
.text:7F02731C mov ebx, [ebp+arg_8] ;我们可以控制的cbSize
.text:7F02731F add ebx, 1Ah ;cbSize+0x1a
.text:7F027322 and ebx, 0FFFFFFFCh ;cbSize+0x1a-4
.text:7F027325 mov eax, large fs:18h
.text:7F02732B mov eax, [eax+30h]
.text:7F02732E push ebx
.text:7F02732F push 0
.text:7F027331 push dword ptr [eax+18h]
.text:7F027334 call ds:RtlAllocateHeap ;按我们设置的cbSize分配cbSize+0x16长度的内存
.text:7F02733A test eax, eax
.text:7F02733C jz short loc_7F027385
.text:7F02733E mov ecx, [ebp+arg_4]
.text:7F027341 mov [eax+0Ch], ecx
.text:7F027344 mov ecx, [ebp+arg_8]
.text:7F027347 mov [eax+10h], ecx
.text:7F02734A mov edx, ecx
.text:7F02734C shr ecx, 2
.text:7F02734F sub ebx, 8
.text:7F027352 mov [eax+8], ebx
.text:7F027355 lea edi, [eax+14h]
.text:7F027358 rep movsd ;拷贝,可触发内存错误**
.text:7F02735A mov ecx, edx
.text:7F02735C and ecx, 3
.text:7F02735F rep movsb
.text:7F027361 mov ecx, [ebp-4]
.text:7F027364 mov edi, [ebp+arg_14]
.text:7F027367 lea edx, [ecx+48h]
.text:7F02736A mov esi, [edx+4]
.text:7F02736D mov [eax+4], esi
一个例子:
...0502000026001610FFFF4444444444444444...
解决方案:
在Microsoft未发布新的补丁前请注销Windows图形和传真查看器(Shimgvw.dll),具体可参考MS06-001的变通办法。
致谢:
感谢我的朋友们。
声明:
本文涉及技术知识仅供仅供安全研究与教学之用,使用者风险自负!