macOS / iOS CoreText越界读取

  • A+
所属分类:移动安全

CVE ID

CVE-2021-1758

测试版本

  • macOS Catalina 10.15.4(19E287)

产品网址

  • https://apple.com


漏洞描述

该漏洞存在于libFontParser.dylib中CoreText的一部分广泛用于macOS,iOS,iPadOS中以解析和绘制文本。此漏洞使攻击者可以从CoreText读取使用API的应用程序的内存


技术细节

漏洞

macOS / iOS创建的字体格式结构是Type 1 Postscript字体的包装,TrueType字体是Mac Resource Fork字体。CoreText是用于绘制文本的框架,该框架支持通过API CoreText CTFontManagerCreateFontDescriptorsFromURL加载Mac资源叉字体

Mac Resource Fork字体的前12个字节是标题长度,资源数据偏移量,资源数据长度。Mac Resource Fork字体标题是通过将资源数据偏移量与文件开头相加来计算的。该漏洞存在于libFontParser.dylib CheckMapCommon中该漏洞可处理Mac Resource Fork字体标题验证。

__int64 __fastcall CheckMapCommon(unsigned int *buf, __int64 rfork_header_ptr){...  rfork_len_map = _byteswap_ulong(buf[3]);  rfork_len = _byteswap_ulong(buf[2]);  v4 = rfork_len + _byteswap_ulong(*buf);  rfork_headr_ptr = rfork_len_map + _byteswap_ulong(buf[1]);  if ( v4 > rfork_headr_ptr )    rfork_headr_ptr = v4;  if ( rfork_headr_ptr > 0xFFFFFE )    goto LABEL_25;  offset_to_typelist = *(unsigned __int16 *)(rfork_header_ptr + 24);  if ( _bittest(&offset_to_typelist, 8u) )    goto LABEL_25;  offset_to_typelist_ = __ROL2__(offset_to_typelist, 8);  end_map_ptr = rfork_header_ptr + rfork_len_map;  cur_rfork_header_ptr = rfork_header_ptr + offset_to_typelist_ + 2;  if ( cur_rfork_header_ptr > end_map_ptr )    goto LABEL_25;  v10 = (_WORD *)(rfork_header_ptr + offset_to_typelist_);  n_in_type = __ROL2__(*v10, 8) + 1; // n_in_type = 0xFFFF + 1 = 0  if ( n_in_type < 0 || end_map_ptr < cur_rfork_header_ptr + 8LL * n_in_type )    goto LABEL_25;  offset_typelist = *(_WORD *)(rfork_header_ptr + 26);  if ( offset_typelist == -1 )  {    v13 = 0LL;  }  else  {    v13 = (unsigned __int16)__ROL2__(offset_typelist, 8) + rfork_ptr;    if ( v13 > end_map_ptr )      goto LABEL_25;  }  if ( n_in_type <= 0 ) // bug here will skip the rest of validation    return 0; // return true...

Mac Resource Header具有3个值:

offset_to_typelist,offset_to_name_type_list,num_type_list是*(_ WORD *)(rfork_header_ptr + 24),*(_ WORD *)(rfork_header_ptr + 26),*(_ WORD *)(rfork_header_ptr + 28)

可以通过修改offset_to_typelist来破坏函数libFontParser.dylib CheckMapCommon使其指向包含0xFFFF(n_in_type)的内存指针,然后将n_in_type自动加1,因为结果n_in_type为零。之后,libFontParser.dylib将检查n_in_type小于或等于零(如果返回true)。 CheckMapCommon稍后,libFontParser.dylib将调用GetResourcePtrCommon以从资源映射中获取资源。

_DWORD *__fastcall GetResourcePtrCommon(__int64 a1, void *tag_name, __int16 a3, int a4, _QWORD *a5, _DWORD *a6, __int128 a7)
{
num_typelist = __ROL2__(rfork_header_ptr[14], 8) + 1;
typelist_ptr = (signed __int64)(a7 == 0 ? 0LL : (_WORD *)((char *)rfork_header_ptr + (unsigned __int16)__ROL2__(rfork_header_ptr[13], 8)));
if ( num_typelist <= 0 )
return 0LL;
v10 = num_typelist;
cur_ptr = rfork_header_ptr + 18;
result = 0LL;
while ( _byteswap_ulong(*(_DWORD *)(cur_ptr - 3)) != (_DWORD)tag_name )
{
cur_ptr += 4;
v13 = __OFSUB__(v10--, 1);
if ( (unsigned __int8)((v10 < 0) ^ v13) | (v10 == 0) )
return result;
}
v29 = a6;
v28 = a1;
v30 = a5;
v14 = (unsigned __int16)__ROL2__(*(cur_ptr - 1), 8) + 1;
relist_offset = (_DWORD *)((char *)rfork_header_ptr + (unsigned __int16)__ROL2__(*cur_ptr, 8) + 32);
v16 = v31 - 1;
while ( !(_QWORD)a7 )
{
if ( v31 == -1 )
{
if ( __ROL2__(*((_WORD *)relist_offset - 2), 8) == attribue )
goto LABEL_21;
}
else if ( !v16 )
{
goto LABEL_21;
}
LABEL_19:
relist_offset += 3;
--v16;
v13 = __OFSUB__(v14--, 1);
if ( (unsigned __int8)((v14 < 0) ^ v13) | (v14 == 0) )
return 0LL;
}
v17 = *((_WORD *)relist_offset - 1);
if ( v17 == -1 || !(unsigned __int8)_EqualString(a7, v9 + (unsigned __int16)__ROL2__(v17, 8), 0LL, 1LL) )
goto LABEL_19;
LABEL_21:
v18 = *vptr & 0xFFFFFF00;
if ( v29 )
*v29 = (signed __int16)__ROL2__(*((_WORD *)vptr - 2), 8);
off_1 = _byteswap_ulong(v18);
if ( *((_QWORD *)&a7 + 1) )
{
typelist_name_offset = *((_WORD *)vptr - 1);
if ( typelist_name_offset == -1 )
**((_BYTE **)&a7 + 1) = 0;
else
memmove( // abuse be OOB read
*((void **)&a7 + 1),
(const void *)(typelist_ptr + (unsigned __int16)__ROL2__(typelist_name_offset, 8)),
*(unsigned __int8 *)(typelist_ptr + (unsigned __int16)__ROL2__(typelist_name_offset, 8)) + 1LL);// sadly length of typelist_name is only maxium 0x100
}
}

由于libFontParser.dylib CheckMapCommon不会为每个资源条目验证typelist_name_offset,因此攻击者可以根据需要修改此值,从而导致越界读取。


重现漏洞

使用cilile.cc验证漏洞

clang++ harness.cc -o harness -framework ApplicationServices -framework CoreFoundation -framework CoreText -framework CoreGraphics --std=c++14 -fsanitize=addressDYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib ./harness ./sfnt_patch.dfontGuardMalloc[harness-1905]: Allocations will be placed on 16 byte boundaries.GuardMalloc[harness-1905]:  - Some buffer overruns may not be noticed.GuardMalloc[harness-1905]:  - Applications using vector instructions (e.g., SSE) should work.GuardMalloc[harness-1905]: version 064535.38AddressSanitizer:DEADLYSIGNAL===================================================================1905==ERROR: AddressSanitizer: SEGV on unknown address 0x640004baf6d2 (pc 0x7fff54430de6 bp 0x7ffee440d890 sp 0x7ffee440d840 T0)==1905==The signal is caused by a READ memory access.    #0 0x7fff54430de5 in GetResourcePtrCommon (libFontParser.dylib:x86_64+0x70de5)    #1 0x7fff54430e7b in FPRMGetIndexedResource (libFontParser.dylib:x86_64+0x70e7b)    #2 0x7fff543c469e in TResourceForkFileReference::GetIndexedResource(unsigned int, unsigned int, short*, unsigned long*, unsigned char*) const (libFontParser.dylib:x86_64+0x469e)    #3 0x7fff543c4626 in TResourceFileDataReference::TResourceFileDataReference(TResourceForkSurrogate const&, unsigned int, unsigned int) (libFontParser.dylib:x86_64+0x4626)    #4 0x7fff543c454f in TResourceFileDataSurrogate::TResourceFileDataSurrogate(TResourceForkSurrogate const&, unsigned int, unsigned int) (libFontParser.dylib:x86_64+0x454f)    #5 0x7fff54413914 in TFont::CreateFontEntities(char const*, bool, bool&, short, char const*, bool) (libFontParser.dylib:x86_64+0x53914)    #6 0x7fff54416482 in TFont::CreateFontEntitiesForFile(char const*, bool, bool, short, char const*) (libFontParser.dylib:x86_64+0x56482)    #7 0x7fff543c103d in FPFontCreateFontsWithPath (libFontParser.dylib:x86_64+0x103d)    #8 0x7fff381a75ee in create_private_data_array_with_path (CoreGraphics:x86_64h+0xa5ee)    #9 0x7fff381a730b in CGFontCreateFontsWithPath (CoreGraphics:x86_64h+0xa30b)    #10 0x7fff381a6f56 in CGFontCreateFontsWithURL (CoreGraphics:x86_64h+0x9f56)    #11 0x7fff39b842ad in CreateFontsWithURL(__CFURL const*, bool) (CoreText:x86_64+0xe2ad)    #12 0x7fff39c82024 in CTFontManagerCreateFontDescriptorsFromURL (CoreText:x86_64+0x10c024)    #13 0x10b7f1d7c in load_font_from_path(char*) (harness:x86_64+0x100001d7c)    #14 0x10b7f2dd1 in main (harness:x86_64+0x100002dd1)    #15 0x7fff71ce6cc8 in start (libdyld.dylib:x86_64+0x1acc8)
==1905==Register values:rax = 0x000000000000dead rbx = 0x0000000000000400 rcx = 0x00007ffee440d8cc rdx = 0x0000000000000010rdi = 0x0000640004ba3fc0 rsi = 0x0000640004baf6d2 rbp = 0x00007ffee440d890 rsp = 0x00007ffee440d840 r8 = 0x00007ffee440d8c0 r9 = 0x00007ffee440d8cc r10 = 0x0000640004ba1825 r11 = 0xffffffffffffffffr12 = 0x0000000000000000 r13 = 0x0000640004ba188f r14 = 0x0000640004ba3fc0 r15 = 0x0000640004ba1825AddressSanitizer can not provide additional info.SUMMARY: AddressSanitizer: SEGV (libFontParser.dylib:x86_64+0x70de5) in GetResourcePtrCommon==1905==ABORTING[1] 1905 abort DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib ./harness

通过运行此命令FontBook进行验证

DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib <path>/Font Book.app/Contents/MacOS/Font Book

使用sfnt_patch.dfont打开,然后在“崩溃报告”选项卡中打开Console.app我们可以看到该进程FontValidator崩溃了

Process:               FontValidator [67246]Path:                  /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Support/FontValidatorIdentifier:            FontValidatorVersion:               493.0.4.1Code Type:             X86-64 (Native)Parent Process:        ??? [1]Responsible:           FontValidator [67246]User ID:               501
Date/Time: 2020-04-18 03:16:40.406 -0700OS Version: Mac OS X 10.15.4 (19E266)Report Version: 12Anonymous UUID: 650A797B-F8B4-2013-399D-4036C2748CEA
Sleep/Wake UUID: 2FFD7BD7-F3AC-4628-9F52-8126DDA57B60
Time Awake Since Boot: 630000 seconds
System Integrity Protection: disabled
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_ACCESS (SIGSEGV)Exception Codes: KERN_INVALID_ADDRESS at 0x000000010a5c36d2Exception Note: EXC_CORPSE_NOTIFY
Termination Signal: Segmentation fault: 11Termination Reason: Namespace SIGNAL, Code 0xbTerminating Process: exc handler [67246]
VM Regions Near 0x10a5c36d2: mapped file 000000010a5b4000-000000010a5b6000 [ 8K] r--/rwx SM=COW --> Dispatch continuations 000000010a600000-000000010aa00000 [ 4096K] rw-/rwx SM=PRV

缓解措施

  • 确保启用Apple Sandbox。

  • 避免使用API CTFontManagerCreateFontDescriptorsFromURL打开不受信任的字体,并使用FontBook安装字体

  • 避免从unknow源安装不受信任的字体

时间线

  • 2020-09-17向供应商报告,供应商于当日确认

  • 2021-02-01供应商修复了漏洞


原文翻译自:https://starlabs.sg/advisories/21-1758/

macOS / iOS CoreText越界读取

本文始发于微信公众号(Ots安全):macOS / iOS CoreText越界读取

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: