高级安全专家Hossein Lotfi
2016年12月14日更新: 在分析Microsoft修复程序期间,我们确认仍未修复相关错误。因此,又发布了一个Secunia咨询SA74000 [5]来解决这个问题。
On December 13, 2016, Microsoft released updates that fix two vulnerabilities reported由Secunia Research提供。 Both can be exploited through a specially crafted font file. One vulnerability results in a Denial of Service (DoS) or a privilege escalation and the other allows a compromise of a vulnerable system even.
本文的目的是提供有关第二个漏洞的详细信息,该漏洞是基于堆的缓冲区溢出漏洞,该漏洞由Microsoft Unicode脚本处理器(属于Microsoft Windows操作系统)中的整数溢出错误引起。此漏洞已分配了常见漏洞和披露(CVE)标识符CVE-2016-7274,并在Microsoft安全公告MS16-147 [1]和Secunia Advisory SA70000 [2]中进行了概述。由于该漏洞最终通过远程提供的True Type字体(TTF)文件导致受影响的系统受到威胁,因此Secunia Advisory SA70000的等级为“Highly Critical”由Secunia Research提供。
通常,可以通过特制网页在基于Web的方案中利用这种漏洞,而指向此类网页的链接可能会通过电子邮件发送给毫无戒心的受害者。此外,攻击者还可以创建嵌入了特制字体文件的文档,然后将其发送给受害者。打开此类特制的网页或文档后,利用可能会在受影响的系统上成功进行。
介绍:
Uniscribe是Microsoft Windows服务集,用于呈现Unicode编码的文本,尤其是复杂的文本布局[3]。在Windows 8和8.1中,实现从USP10.dll(DLL,动态链接库)移向GDI32.dll。在Windows 10中,该功能在GDI32full.dll中实现。
请注意,以下分析是在Windows 10 Enterprise上使用GDI32full.dll版本10.0.14393.206进行的。
再生产:
Windows 10企业版的默认安装总共包含119个TTF文件。仅需稍加修改即可使用其中两个来轻松触发此问题:Microsoft PhagsPa(phagspa.ttf)和Microsoft PhagsPa Bold(phagspab.ttf)。
为了进行复制,请在十六进制编辑器中打开文件“ C:\ Windows \ Fonts \ phagspa.ttf”,并将偏移量0x2051的值从0x00000006更改为0x33333334。
技术细节:
在处理字体文件中的脚本期间,代码流到达“LoadFont()”GDI32full.dll中的函数。此后不久,此函数调用“GetFontDesc()”函数加载字体内字符代码的映射。
.text:750F42CA ; __int32 __stdcall LoadFont(HDC, struct FACE_CACHE *) .text:750F42CA var_260 = dword ptr -260h .text:750F42CA var_25C = dword ptr -25Ch .text:750F42CA var_258 = dword ptr -258h .text:750F42CA var_254 = dword ptr -254h .text:750F42CA var_250 = dword ptr -250h .text:750F42CA lpMem = dword ptr -24Ch .text:750F42CA Dst = byte ptr -248h .text:750F42CA var_24 = HDC__ ptr -24h .text:750F42CA var_4 = dword ptr -4 .text:750F42CA .text:750F42CA ; FUNCTION CHUNK AT .text:7512EDD3 SIZE 000001F7 BYTES .text:750F42CA .text:750F42CA mov edi, edi .text:750F42CC push ebp .text:750F42CD mov ebp, esp .text:750F42CF sub esp, 264h .text:750F42D5 mov eax, ___security_cookie .text:750F42DA xor eax, ebp .text:750F42DC mov [ebp+var_4], eax .text:750F42DF push ebx .text:750F42E0 push esi ; unsigned __int32 * .text:750F42E1 push edi ; union FONTUVSENTRY * .text:750F42E2 xor ebx, ebx .text:750F42E4 mov [ebp+var_250], ecx .text:750F42EA and [ebp+var_254], ebx .text:750F42F0 lea eax, [ebp+Dst] .text:750F42F6 push 220h ; Size .text:750F42FB push ebx ; Val .text:750F42FC push eax ; Dst .text:750F42FD mov esi, edx .text:750F42FF mov [ebp+lpMem], ebx .text:750F4305 call _memset .text:750F430A add esp, 0Ch .text:750F430D lea edi, [ebp+var_24] .text:750F4310 push 8 .text:750F4312 pop eax .text:750F4313 mov ecx, eax .text:750F4315 xor eax, eax .text:750F4317 rep stosd .text:750F4319 mov eax, 0F807h .text:750F431E and [esi+0A0h], ax .text:750F4325 mov al, [esi+95h] .text:750F432B and al, 0Ch .text:750F432D cmp al, 8 .text:750F432F jz loc_7512EDD3 .text:750F4335 .text:750F4335 loc_750F4335: ; CODE XREF: LoadFont(HDC__ *,FACE_CACHE *)+3AB0F_j .text:750F4335 mov ecx, [ebp+var_250] .text:750F433B lea eax, [ebp+lpMem] .text:750F4341 lea edi, [esi+98h] .text:750F4347 push eax ; HDC .text:750F4348 mov edx, edi .text:750F434A call GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)
的“GetFontDesc()”函数首先检查“OS/2”表,然后从cmap表加载数据。
.text:750F6618 ; __int32 __stdcall GetFontDesc(HDC, int *, struct FONTCMAPDESC **) .text:750F6618 hdc = dword ptr -30h .text:750F6618 var_2C = dword ptr -2Ch .text:750F6618 var_28 = dword ptr -28h .text:750F6618 var_24 = dword ptr -24h .text:750F6618 pvBuffer = dword ptr -20h .text:750F6618 var_1C = dword ptr -1Ch .text:750F6618 var_18 = dword ptr -18h .text:750F6618 var_14 = dword ptr -14h .text:750F6618 var_10 = dword ptr -10h .text:750F6618 var_C = dword ptr -0Ch .text:750F6618 var_8 = dword ptr -8 .text:750F6618 var_4 = dword ptr -4 .text:750F6618 arg_0 = dword ptr 8 .text:750F6618 .text:750F6618 ; FUNCTION CHUNK AT .text:7512F8E4 SIZE 0000007C BYTES .text:750F6618 .text:750F6618 mov edi, edi .text:750F661A push ebp .text:750F661B mov ebp, esp .text:750F661D sub esp, 30h .text:750F6620 and [ebp+var_C], 0 .text:750F6624 lea eax, [ebp+pvBuffer] .text:750F6627 push ebx .text:750F6628 push esi ; int .text:750F6629 push edi ; unsigned __int32 * .text:750F662A mov edi, [ebp+arg_0] .text:750F662D mov ebx, ecx .text:750F662F push 4 ; cjBuffer .text:750F6631 push eax ; pvBuffer .text:750F6632 push 3Eh ; dwOffset .text:750F6634 and dword ptr [edi], 0 .text:750F6637 mov esi, edx .text:750F6639 push '2/SO' ; dwTable .text:750F663E push ebx ; hdc .text:750F663F mov [ebp+var_18], esi .text:750F6642 mov [ebp+hdc], ebx .text:750F6645 call ds:[email protected] ; GetFontData(x,x,x,x,x) .text:750F664B cmp eax, 4 .text:750F664E jnz loc_750F68B2 .text:750F6654 mov al, byte ptr [ebp+pvBuffer+2] .text:750F6657 cmp al, 0F0h .text:750F6659 jnb short loc_750F665F .text:750F665B test al, al .text:750F665D jnz short loc_750F666A .text:750F665F .text:750F665F loc_750F665F: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+41_j .text:750F665F mov eax, [ebp+pvBuffer] .text:750F6662 test al, al .text:750F6664 jnz loc_7512F8E4 .text:750F666A .text:750F666A loc_750F666A: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+45_j .text:750F666A or dword ptr [esi], 0FFFFFFFFh .text:750F666D .text:750F666D loc_750F666D: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+392D1_j .text:750F666D xor eax, eax .text:750F666F push eax ; cjBuffer .text:750F6670 push eax ; pvBuffer .text:750F6671 push eax ; dwOffset .text:750F6672 push 'pamc' ; dwTable .text:750F6677 push ebx ; hdc .text:750F6678 call ds:[email protected] ; GetFontData(x,x,x,x,x) .text:750F667E mov ebx, eax .text:750F6680 cmp ebx, 0FFFFFFFFh .text:750F6683 jz loc_7512F955 .text:750F6689 cmp ebx, 4 .text:750F668C jl loc_7512F955 .text:750F6692 push edi ; int .text:750F6693 lea ecx, [ebx+34h] .text:750F6696 push ecx ; dwBytes .text:750F6697 call [email protected] ; UspAllocCache(x,x) .text:750F669C test eax, eax .text:750F669E js loc_7512F955 .text:750F66A4 mov ecx, [edi] .text:750F66A6 push ebx ; cjBuffer .text:750F66A7 lea eax, [ecx+34h] .text:750F66AA mov [ecx+4], eax .text:750F66AD mov eax, [edi] .text:750F66AF mov [eax+8], ebx .text:750F66B2 mov eax, [edi] .text:750F66B4 push dword ptr [eax+4] ; pvBuffer .text:750F66B7 push 0 ; dwOffset .text:750F66B9 push 'pamc' ; dwTable .text:750F66BE push [ebp+hdc] ; hdc .text:750F66C1 call ds:[email protected] ; GetFontData(x,x,x,x,x)
根据加载的信息,进行检查以确保有足够的数据可用,并且至少有一个EncodingRecord表。
.text:750F66CF mov eax, [edi] .text:750F66D1 mov eax, [eax+4] .text:750F66D4 rol word ptr [eax+2], 8 ; numTables .text:750F66D9 mov ecx, [edi] .text:750F66DB mov edx, [ecx+4] .text:750F66DE movzx eax, word ptr [edx+2] .text:750F66E2 mov [ebp+numTables], eax .text:750F66E5 lea eax, ds:4[eax*8 ; needed data .text:750F66EC cmp ebx, eax ; check if enough data is available. .text:750F66EE jl loc_7512F8EE .text:750F66F4 lea eax, [edx+4] .text:750F66F7 xor edx, edx .text:750F66F9 and [ecx+2Ch], edx .text:750F66FC and [ebp+var_8], edx .text:750F66FF and [ebp+var_10], edx .text:750F6702 mov [ebp+var_14], eax .text:750F6705 mov eax, [edi] .text:750F6707 mov [ebp+var_4], edx .text:750F670A and [eax+30h], edx .text:750F670D mov eax, [ebp+numTables] ; check if numTables is zero .text:750F6710 test eax, eax .text:750F6712 jle cleanup_and_return
之后,进入一个循环以处理可用的EncodingRecords。如果平台ID为0,编码ID为5,子表格式为14 [4],则该记录将被视为“ Unicode变异序列”(UVS)记录,并且将UVS子表的偏移量和大小保存在处理对象中,以用于以后处理。
loc_750F671E: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+1B0_j .text:750F671E xor edx, edx .text:750F6720 inc edx .text:750F6721 xor eax, eax .text:750F6723 .text:750F6723 loc_750F6723: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+114_j .text:750F6723 rol word ptr [ecx+eax*2], 8 .text:750F6728 inc eax .text:750F6729 cmp eax, 2 .text:750F672C jl short loc_750F6723 .text:750F672E lea esi, [ecx+4] .text:750F6731 mov ecx, esi .text:750F6733 call [email protected]@[email protected] ; FlipDWords(ulong *,int) .text:750F6738 movzx ecx, word ptr [esi-2] ; encodingID .text:750F673C mov esi, [esi] .text:750F673E mov [ebp+var_28], esi ; offset .text:750F6741 test esi, esi .text:750F6743 jz continue_loop .text:750F6749 lea eax, [ebx-4] .text:750F674C cmp eax, esi .text:750F674E jbe continue_loop .text:750F6754 mov edx, [edi] .text:750F6756 mov eax, [edx+4] .text:750F6759 add eax, esi .text:750F675B mov esi, [ebp+var_14] .text:750F675E mov [ebp+encoding_subtable_offset], eax ; encoding_subtable_offset .text:750F6761 mov ax, [eax] .text:750F6764 rol ax, 8 .text:750F6768 movzx eax, ax .text:750F676B mov [ebp+var_2C], eax .text:750F676E movzx eax, word ptr [esi] ; platformID .text:750F6771 test ax, ax .text:750F6774 jz loc_750F689B .text:750F677A push 3 .text:750F677C pop edx .text:750F677D cmp ax, dx .text:750F6780 jnz continue_loop .text:750F6786 xor eax, eax .text:750F6788 inc eax .text:750F6789 test cx, cx .text:750F678C jz short loc_750F679A .text:750F678E cmp cx, ax .text:750F6791 jnz loc_750F68BA .text:750F6797 push 2 .text:750F6799 pop eax .text:750F679A .text:750F679A loc_750F679A: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+174_j .text:750F679A cmp [ebp+var_10], eax .text:750F679D jge continue_loop .text:750F67A3 mov [ebp+var_10], eax .text:750F67A6 .text:750F67A6 loc_750F67A6: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+2B2_j .text:750F67A6 mov eax, [ebp+var_2C] .text:750F67A9 mov esi, [ebp+encoding_subtable_offset] .text:750F67AC mov edx, [ebp+var_28] .text:750F67AF movzx eax, ax .text:750F67B2 mov [ebp+var_8], esi .text:750F67B5 mov [ebp+var_4], edx .text:750F67B8 mov [ebp+var_C], eax .text:750F67BB .text:750F67BB loc_750F67BB: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+295_j .text:750F67BB mov ecx, [ebp+var_14] .text:750F67BE add ecx, 8 .text:750F67C1 sub [ebp+num_Tables], 1 .text:750F67C5 mov [ebp+var_14], ecx .text:750F67C8 jnz loc_750F671E
…
.text:750F689B loc_750F689B: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+15C_j .text:750F689B cmp ecx, 5 ;encoding ID = 5? .text:750F689E jz loc_7512F8F1
…
.text:7512F8F1 loc_7512F8F1: ; CODE XREF: GetFontDesc(HDC__ *,int *,FONTCMAPDESC * *)+286_j .text:7512F8F1 mov eax, [ebp+var_2C] .text:7512F8F4 cmp ax, 0Eh ; is subtable format 14? .text:7512F8F8 jnz continue_loop .text:7512F8FE cmp dword ptr [edx+2Ch], 0 ; just one record allowed. .text:7512F902 jnz continue_loop .text:7512F908 mov ecx, ebx .text:7512F90A sub ecx, [ebp+var_28] .text:7512F90D push 0Ah .text:7512F90F pop eax .text:7512F910 cmp ecx, eax .text:7512F912 jl continue_loop .text:7512F918 mov esi, [ebp+encoding_subtable_offset] .text:7512F91B mov [edx+2Ch], esi ; UVS_subtable_offset .text:7512F91E mov eax, [edi] .text:7512F920 mov [eax+30h], ecx ; UVS_subtable_size .text:7512F923 jmp continue_loop
从该函数返回后,代码最终调用“ LoadUvsTable()”函数来处理可能遇到的UVS表。
.text:750F4446 xor edx, edx ; passing zero. Just return space needed. .text:750F4448 push edi ; struct FONTCMAPDESC * .text:750F4449 mov ecx, ebx .text:750F444B mov [ebp+var_258], edi .text:750F4451 call LoadUvsTable (FONTCMAPDESC *,FONTUVSENTRY *,ulong *)
首先,该函数通过验证是否设置了UVS_subtable_offset来检查是否找到了UVS记录。
.text:750F5DB2 ; __int32 __stdcall LoadUvsTable(struct FONTCMAPDESC *, union FONTUVSENTRY *, unsigned __int32 *) .text:750F5DB2 var_2C= dword ptr -2Ch .text:750F5DB2 var_28= dword ptr -28h .text:750F5DB2 var_24= dword ptr -24h .text:750F5DB2 var_20= dword ptr -20h .text:750F5DB2 var_1C= dword ptr -1Ch .text:750F5DB2 var_18= dword ptr -18h .text:750F5DB2 var_14= dword ptr -14h .text:750F5DB2 var_10= dword ptr -10h .text:750F5DB2 var_C= dword ptr -0Ch .text:750F5DB2 var_8= dword ptr -8 .text:750F5DB2 var_4= dword ptr -4 .text:750F5DB2 arg_0= dword ptr 8 .text:750F5DB2 .text:750F5DB2 ; FUNCTION CHUNK AT .text:7512F4CE SIZE 000001D4 BYTES .text:750F5DB2 .text:750F5DB2 mov edi, edi .text:750F5DB4 push ebp .text:750F5DB5 mov ebp, esp .text:750F5DB7 sub esp, 2Ch .text:750F5DBA mov eax, [ebp+arg_0] .text:750F5DBD push ebx .text:750F5DBE mov [ebp+var_C], edx .text:750F5DC1 xor edx, edx .text:750F5DC3 mov [ebp+var_10], edx .text:750F5DC6 mov ebx, [eax] .text:750F5DC8 mov [ebp+var_2C], ebx .text:750F5DCB push esi .text:750F5DCC push edi .text:750F5DCD test ecx, ecx .text:750F5DCF jz short loc_750F5DDC .text:750F5DD1 mov ebx, [ecx+2Ch] ; is UVS_subtable_offset set? .text:750F5DD4 test ebx, ebx .text:750F5DD6 jnz loc_7512F4CE ; is UVS_subtable_size set?
经过一些完整性检查后,将提取变体选择器记录的数量。
.text:7512F4CE cmp dword ptr [ecx+30h], 0Ah ; at least one variation Selector Record data available? .text:7512F4D2 jb loc_750F5DDC .text:7512F4D8 movzx esi, byte ptr [ebx+2] .text:7512F4DC movzx eax, byte ptr [ebx+3] .text:7512F4E0 shl esi, 8 .text:7512F4E3 or esi, eax .text:7512F4E5 movzx eax, byte ptr [ebx+4] .text:7512F4E9 shl esi, 8 .text:7512F4EC or esi, eax .text:7512F4EE movzx eax, byte ptr [ebx+5] .text:7512F4F2 shl esi, 8 .text:7512F4F5 or esi, eax ; extracted_size_from_subtable .text:7512F4F7 cmp esi, [ecx+30h] .text:7512F4FA ja loc_750F5DDE .text:7512F500 movzx edi, byte ptr [ebx+6] .text:7512F504 movzx eax, byte ptr [ebx+7] .text:7512F508 shl edi, 8 .text:7512F50B or edi, eax .text:7512F50D movzx eax, byte ptr [ebx+8] .text:7512F511 shl edi, 8 .text:7512F514 or edi, eax .text:7512F516 movzx eax, byte ptr [ebx+9] .text:7512F51A shl edi, 8 .text:7512F51D or edi, eax ; Number of variation selector records .text:7512F51F imul eax, edi, 0Bh .text:7512F522 add eax, 0Ah .text:7512F525 cmp esi, eax ; enough data available in subtable? .text:7512F527 jb loc_750F5DDE .text:7512F52D and [ebp+var_18], edx .text:7512F530 lea eax, [ebx+0Ah] .text:7512F533 and [ebp+var_24], edx .text:7512F536 mov [ebp+var_28], eax .text:7512F539 test edi, edi ; No variation selector records? .text:7512F53B jz return
然后进入一个循环,以查看需要多少空间来处理变化选择器记录。这是通过计算所有记录中范围的总数来完成的。对于每个提取的记录范围编号,将进行检查以查看是否有足够的数据可用。请注意,此处存在整数溢出错误,可用于绕过此检查。由于在调用此函数时未传递任何缓冲区,因此仅返回计算出的缓冲区大小。
.text:7512F547 movzx eax, byte ptr [eax] .text:7512F54A movzx ecx, byte ptr [edx-8] .text:7512F54E shl eax, 8 .text:7512F551 or ecx, eax .text:7512F553 movzx eax, byte ptr [edx-7] .text:7512F557 shl ecx, 8 .text:7512F55A or ecx, eax .text:7512F55C mov [ebp+var_20], ecx .text:7512F55F cmp [ebp+var_18], ecx .text:7512F562 jnb loc_750F5DDE .text:7512F568 movzx eax, byte ptr [edx-1] .text:7512F56C mov [ebp+var_18], ecx .text:7512F56F movzx ecx, byte ptr [edx-2] .text:7512F573 shl ecx, 8 .text:7512F576 or ecx, eax .text:7512F578 movzx eax, byte ptr [edx] .text:7512F57B shl ecx, 8 .text:7512F57E or ecx, eax .text:7512F580 movzx eax, byte ptr [edx+1] .text:7512F584 shl ecx, 8 .text:7512F587 or ecx, eax .text:7512F589 jz loc_7512F66B .text:7512F58F lea eax, [ecx+4] .text:7512F592 cmp eax, ecx .text:7512F594 jb loc_750F5DDE .text:7512F59A cmp eax, esi .text:7512F59C ja loc_750F5DDE .text:7512F5A2 lea edx, [ecx+ebx] .text:7512F5A5 movzx eax, byte ptr [edx] .text:7512F5A8 shl eax, 8 .text:7512F5AB mov [ebp+var_4], eax .text:7512F5AE movzx eax, byte ptr [edx+1] .text:7512F5B2 or [ebp+var_4], eax .text:7512F5B5 movzx eax, byte ptr [edx+2] .text:7512F5B9 shl [ebp+var_4], 8 .text:7512F5BD or [ebp+var_4], eax .text:7512F5C0 movzx eax, byte ptr [edx+3] .text:7512F5C4 shl [ebp+var_4], 8 .text:7512F5C8 mov [ebp+var_1C], edx .text:7512F5CB mov edx, [ebp+var_4] .text:7512F5CE or edx, eax .text:7512F5D0 mov [ebp+var_4], edx ; numUnicodeValueRanges .text:7512F5D3 imul edx, 5 ; *** Integer Overflow *** .text:7512F5D6 push esi .text:7512F5D7 add edx, 4 .text:7512F5DA call CheckBuffer .text:7512F5DF test eax, eax .text:7512F5E1 jz loc_750F5DDE .text:7512F5E7 mov edx, [ebp+var_1C] .text:7512F5EA add edx, 4 .text:7512F5ED cmp [ebp+var_C], 0 ; is a buffer passed? .text:7512F5F1 jz short loc_7512F65F .text:7512F5F3 and [ebp+var_1C], 0 .text:7512F5F7 cmp [ebp+var_4], 0 .text:7512F5FB jbe short loc_7512F668 .text:7512F5FD mov ecx, [ebp+var_20] .text:7512F600 .text:7512F600 ; CODE XREF: LoadUvsTable(FONTCMAPDESC *,FONTUVSENTRY *,ulong *)+398A9_j .text:7512F600 movzx eax, byte ptr [edx] .text:7512F603 shl eax, 8 .text:7512F606 mov [ebp+var_8], eax .text:7512F609 movzx eax, byte ptr [edx+1] .text:7512F60D or [ebp+var_8], eax .text:7512F610 shl [ebp+var_8], 8 .text:7512F614 movzx eax, byte ptr [edx+2] .text:7512F618 or [ebp+var_8], eax .text:7512F61B jbe loc_750F5DDE .text:7512F621 mov eax, [ebp+var_10] .text:7512F624 inc eax .text:7512F625 mov [ebp+var_10], eax .text:7512F628 cmp [ebp+var_2C], eax .text:7512F62B jb short loc_7512F698 .text:7512F62D mov eax, [ebp+var_C] .text:7512F630 mov [eax+4], ecx .text:7512F633 mov ecx, [ebp+var_C] .text:7512F636 mov eax, [ebp+var_8] .text:7512F639 add [ebp+var_C], 0Ah .text:7512F63D mov [ecx], eax .text:7512F63F mov ax, [edx+3] .text:7512F643 add edx, 5 .text:7512F646 rol ax, 8 .text:7512F64A mov [ecx+8], ax .text:7512F64E mov eax, [ebp+var_1C] .text:7512F651 mov ecx, [ebp+var_20] .text:7512F654 inc eax .text:7512F655 mov [ebp+var_1C], eax .text:7512F658 cmp eax, [ebp+var_4] .text:7512F65B jb short loc_7512F600 .text:7512F65D jmp short loc_7512F668 .text:7512F65F ; --------------------------------------------------------------------------- .text:7512F65F .text:7512F65F; CODE XREF: LoadUvsTable(FONTCMAPDESC *,FONTUVSENTRY *,ulong *)+3983F_j .text:7512F65F mov eax, [ebp+var_10] .text:7512F662 add eax, [ebp+var_4] ; *** Integer Overflow Possibility*** .text:7512F665 mov [ebp+var_10], eax .text:7512F668 .text:7512F668; CODE XREF: LoadUvsTable(FONTCMAPDESC *,FONTUVSENTRY *,ulong *)+39849_j .text:7512F668; LoadUvsTable(FONTCMAPDESC *,FONTUVSENTRY *,ulong *)+398AB_j .text:7512F668 mov edx, [ebp+var_14] .text:7512F66B .text:7512F66B; CODE XREF: LoadUvsTable(FONTCMAPDESC *,FONTUVSENTRY *,ulong *)+397D7_j .text:7512F66B mov ecx, [ebp+var_24] .text:7512F66E add edx, 0Bh .text:7512F671 mov eax, [ebp+var_28] .text:7512F674 inc ecx .text:7512F675 add eax, 0Bh .text:7512F678 mov [ebp+var_24], ecx .text:7512F67B mov [ebp+var_28], eax .text:7512F67E mov [ebp+var_14], edx .text:7512F681 cmp ecx, edi .text:7512F683 jb loc_7512F547
返回时,将计算出的缓冲区大小乘以10,即发生整数溢出错误。这将导致分配的缓冲区过小。
.text:7512EEB9 loc_7512EEB9: ; CODE XREF: LoadFont(HDC__ *,FACE_CACHE *)+19A_j .text:7512EEB9 mov ecx, [edi] .text:7512EEBB test ecx, ecx ; calculated buffer size .text:7512EEBD jz loc_750F446A .text:7512EEC3 lea eax, [esi+410h] .text:7512EEC9 push eax ; int .text:7512EECA mov [ebp+var_25C], eax .text:7512EED0 imul eax, ecx, 0Ah ; *** Integer Overflow *** .text:7512EED3 push eax ; dwBytes .text:7512EED4 call [email protected] ; UspAllocCache(x,x)
对“ LoadUvsTable()”函数的另一个调用是在传递了尺寸不足的缓冲区以执行UVS表的实际加载的情况下完成的。
.text:7512EEE3 mov edx, [esi+410h] .text:7512EEE9 mov ecx, ebx ; allocated undersized buffer .text:7512EEEB push edi ; struct FONTCMAPDESC * .text:7512EEEC call LoadUvsTable(FONTCMAPDESC *,FONTUVSENTRY *,ulong *)
循环用于将数据复制到提供的大小不足的缓冲区,从而导致内存损坏。通过将startUnicodeValue设置为零,可以在需要时退出循环。
.text:7512F600 movzx eax, byte ptr [edx] .text:7512F603 shl eax, 8 .text:7512F606 mov [ebp+var_8], eax .text:7512F609 movzx eax, byte ptr [edx+1] .text:7512F60D or [ebp+var_8], eax .text:7512F610 shl [ebp+var_8], 8 .text:7512F614 movzx eax, byte ptr [edx+2] .text:7512F618 or [ebp+var_8], eax .text:7512F61B jbe loc_750F5DDE ; early exit of loop whenever needed! ;) .text:7512F621 mov eax, [ebp+var_10] .text:7512F624 inc eax .text:7512F625 mov [ebp+var_10], eax .text:7512F628 cmp [ebp+var_2C], eax .text:7512F62B jb short loc_7512F698 .text:7512F62D mov eax, [ebp+var_C] .text:7512F630 mov [eax+4], ecx ; *** Corruption *** .text:7512F633 mov ecx, [ebp+var_C] .text:7512F636 mov eax, [ebp+var_8] .text:7512F639 add [ebp+var_C], 0Ah .text:7512F63D mov [ecx], eax ; *** Corruption *** .text:7512F63F mov ax, [edx+3] .text:7512F643 add edx, 5 .text:7512F646 rol ax, 8 .text:7512F64A mov [ecx+8], ax ; *** Corruption *** .text:7512F64E mov eax, [ebp+var_1C] .text:7512F651 mov ecx, [ebp+var_20] .text:7512F654 inc eax .text:7512F655 mov [ebp+var_1C], eax .text:7512F658 cmp eax, [ebp+var_4] ; big value .text:7512F65B jb short loc_7512F600
内存损坏及其控制最终使攻击者有可能破坏运行受影响的Microsoft Windows操作系统版本的系统。
参考文献:
[1] //technet.microsoft.com/library/security/MS16-147
[2] //secunia.com/advisories/70000
[3] //en.wikipedia.org/wiki/Uniscribe