CVE-2016-7595 Apple macOS/iOS CoreText OTL::GPOS::ApplyPairPos 越界访问漏洞分析

前言

2016年12月的Apple安全公告中(macOS公告iOS公告),修复4个由腾讯安全平台部终端安全团队报告的漏洞,其中有2个是字体解析造成的越界访问漏洞,影响 macOS/iOS/watchOS/tvOS等多个平台系统,本文主要分析其中的 CVE-2016-7595 字体漏洞【图1】。



图1

这个漏洞在报给Apple 17天后发布 macOS 10.2.2 测试版补丁,一个半月后发布安全公告和补丁(包括iOS、watchOS和tvOS),难得看见苹果这么积极一次。

###漏洞分析
此次漏洞是通过Fuzzing发现的,直接对比poc与原始文件的数据,可以发现其实就1个字节的差异(0x00 => 0x6C)【图2】:



图2

用ttx命令分析字体格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
╭─riusksk@MacBook  ~/Downloads ‹›
╰─➤$ ttx poc.ttf
Dumping "poc.ttf" to "poc#1.ttx"...
Dumping 'GlyphOrder' table...
Dumping 'head' table...
Dumping 'hhea' table...
Dumping 'maxp' table...
Dumping 'OS/2' table...
Dumping 'hmtx' table...
Dumping 'cmap' table...
Dumping 'fpgm' table...
Dumping 'prep' table...
Dumping 'cvt ' table...
Dumping 'loca' table...
Dumping 'glyf' table...
Dumping 'name' table...
Dumping 'post' table...
Dumping 'gasp' table...
/usr/local/lib/python2.7/site-packages/FontTools/fontTools/ttLib/tables/otTables.py:60: UserWarning: Coverage table has start glyph ID out of range: glyph27713.
warnings.warn("Coverage table has start glyph ID out of range: %s." % start)
An exception occurred during the decompilation of the 'GPOS' table
Dumping 'GPOS' table...
Dumping 'GSUB' table...
Dumping 'DSIG' table...

从上面的提示可以看出,是在解析GPOS表时,通过glyphIDCoverage表索引时导致越界了,其中glyph27713的数值正是0x6C41(27713),也就是上面图1中文件对比的差异值。虽然这是FontTools工具的错误,不代表Apple系统本身,但它跟Apple系统导致崩溃的是同一字节,从这可以直接得到导致崩溃的关键字节是glyphID值。

GPOS表

TrueType/OpenType字体格式中的GPOS表是用于为字体中文本布局及渲染提供glyph位置信息的表,表中各个字体结构如图3所示:



图3

GPOS表主要包含3个子表:ScriptList、FeatureList和LookupList,本次漏洞主要问题在LookupList子表中的PairAdjustmentPositioning中,PairAdjustmentPositioning子表(PairPos)被用于调整两个glyphs彼此之间的位置。

PairPos表下又包含多个PairSet数组,PairSet数组包含Coverage表中每个glyph对应的偏移量,并按Coverage Index来排序。

PairSet下包含PairValueRecord指定每一glyph配对(pair)中的第二个glyph(SecondGlyph)的glyph名和索引值GlyphID(对应【图3】中glyphRefID),同时包含两个ValueRecord值去指定第一个glyph和第二个glyph的位置信息。

导致越界的漏洞正是用于索引的GlyphID(glyphRefID),用ttx解析原有正常字体文件生成的xml文件,如图4所示,index=”65”就是正常GlyphID值 00 41,如果随便给第1字节设置个值都会导致崩溃。



图4

调试

用lldb调试下,崩溃后的地址及栈回溯如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
(lisa)run poc.ttf 
Process 96714 launched
Process 96714 stopped
* thread #1: tid = 0x3f119d, 0x00007fffa7c01491 CoreText`OTL::GPOS::ApplyPairPos(OTL::LookupSubtable const*, TGlyphIterator&, OTL::Coverage const&) const + 411, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x3007ddfae)
frame #0: 0x00007fffa7c01491 CoreText`OTL::GPOS::ApplyPairPos(OTL::LookupSubtable const*, TGlyphIterator&, OTL::Coverage const&) const + 411
CoreText`OTL::GPOS::ApplyPairPos:
-> 0x7fffa7c01491 <+411>: mov ax, word ptr [r14 + 2*rax + 0xa]
0x7fffa7c01497 <+417>: rol ax, 0x8
0x7fffa7c0149b <+421>: movzx eax, ax
0x7fffa7c0149e <+424>: lea rsi, [r14 + rax]
(lisa)register read rax
rax = 0x00000000ffffffff
(lisa)x $r14+2*$rax+0xa
error: memory read failed for 0x3007c5600

(lisa)bt
* thread #1: tid = 0x3f119d, 0x00007fffa7c01491 CoreText`OTL::GPOS::ApplyPairPos(OTL::LookupSubtable const*, TGlyphIterator&, OTL::Coverage const&) const + 411, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x3007ddfae)
* frame #0: 0x00007fffa7c01491 CoreText`OTL::GPOS::ApplyPairPos(OTL::LookupSubtable const*, TGlyphIterator&, OTL::Coverage const&) const + 411
frame #1: 0x00007fffa7c05907 CoreText`OTL::GPOS::ApplyLookupSubtable(OTL::Lookup const&, unsigned int, OTL::LookupSubtable const*, TGlyphIterator&, OTL::Coverage const&) const + 85
frame #2: 0x00007fffa7c02c7b CoreText`OTL::GPOS::ApplyLookupAt(OTL::Lookup const&, TGlyphIterator&) const + 339
frame #3: 0x00007fffa7b68ff4 CoreText`OTL::GPOS::ApplyLookups(TRunGlue&, int, OTL::GlyphLookups&) const + 448
frame #4: 0x00007fffa7b68897 CoreText`TOpenTypePositioningEngine::PositionRuns(SyncState&, KerningStatus&) + 839
frame #5: 0x00007fffa7b66d05 CoreText`TKerningEngine::PositionGlyphs(TLine&, TCharStream const*) + 347
frame #6: 0x00007fffa7bbe59d CoreText`TTypesetter::FinishLayout(std::__1::tuple<TLine const*, TCharStream const*, void const* (*)(__CTRun const*, __CFString const*, void*), void*, std::__1::shared_ptr<TBidiLevelsProvider>*, unsigned int, unsigned char> const&, TLine&, SyncState) + 35
frame #7: 0x00007fffa7b5586d CoreText`TTypesetterAttrString::Initialize(__CFAttributedString const*) + 865
frame #8: 0x00007fffa7b552ea CoreText`CTLineCreateWithAttributedString + 59
frame #9: 0x00007fffb8be086e UIFoundation`__NSStringDrawingEngine + 10669
frame #10: 0x00007fffb8be69ca UIFoundation`-[NSAttributedString(NSExtendedStringDrawing) boundingRectWithSize:options:context:] + 605
frame #11: 0x00007fffb8bdcc43 UIFoundation`-[NSAttributedString(NSStringDrawing) size] + 59
frame #12: 0x0000000100047d70 Font Book`___lldb_unnamed_symbol1053$$Font Book + 368
frame #13: 0x00000001000476e9 Font Book`___lldb_unnamed_symbol1052$$Font Book + 89
frame #14: 0x00000001000475b0 Font Book`___lldb_unnamed_symbol1049$$Font Book + 774
frame #15: 0x000000010006a2d2 Font Book`___lldb_unnamed_symbol1860$$Font Book + 110
frame #16: 0x000000010005d4ee Font Book`___lldb_unnamed_symbol1545$$Font Book + 2651
frame #17: 0x00007fffa46b2451 AppKit`-[NSApplication _doOpenFile:ok:tryTemp:] + 253
frame #18: 0x00007fffa427f789 AppKit`-[NSApplication finishLaunching] + 1624
frame #19: 0x00007fffa427ed2a AppKit`-[NSApplication run] + 267
frame #20: 0x00007fffa4249a8a AppKit`NSApplicationMain + 1237
frame #21: 0x0000000100001527 Font Book`___lldb_unnamed_symbol1$$Font Book + 11
frame #22: 0x00007fffbb632255 libdyld.dylib`start + 1
frame #23: 0x00007fffbb632255 libdyld.dylib`start + 1

[r14 + 2*rax + 0xa]索引错误,很典型的数组越界指令。

通过设置条件断点去记录获取的GlyphID以及后面的将其传参给OTL::Coverage::SearchFmt2Binary函数后返回值,可以发现最后当GlyphID=0x55(85)时返回值0,最后触发崩溃,所以样本中的GlyphID只要>=0x55都会导致崩溃。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(lisa) p "GlyphID" $eax
(unsigned int) $95 = 85
(lisa) c
Process 25648 resuming
Command #2 'c' continued the target.
(lisa) p "SearchFmt2Binary参数2" $esi
(unsigned int) $96 = 85
(lisa) c
Process 25648 resuming
Command #2 'c' continued the target.
(lisa) p "返回值" $eax
(unsigned int) $97 = 0
(lisa) c
Process 25648 resuming
Command #2 'c' continued the target.
Process 25648 stopped
* thread #1: tid = 0x43fc6, 0x00007fffcb443491 CoreText`OTL::GPOS::ApplyPairPos(OTL::LookupSubtable const*, TGlyphIterator&, OTL::Coverage const&) const + 411, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x3007bc6fe)
frame #0: 0x00007fffcb443491 CoreText`OTL::GPOS::ApplyPairPos(OTL::LookupSubtable const*, TGlyphIterator&, OTL::Coverage const&) const + 411
CoreText`OTL::GPOS::ApplyPairPos:
-> 0x7fffcb443491 <+411>: mov ax, word ptr [r14 + 2*rax + 0xa]
0x7fffcb443497 <+417>: rol ax, 0x8
0x7fffcb44349b <+421>: movzx eax, ax
0x7fffcb44349e <+424>: lea rsi, [r14 + rax]

返回值为0时,经dec减1后为0xFFFFFFFF,以此为索引值,最后导致越界访问。

1
2
dec     eax     ; eax=0xFFFFFFFF
mov ax, [r14+rax*2+0Ah] ; 越界访问,导致崩溃

漏洞修复

苹果已经发布安全补丁,macOS用户可升级到10.12.2,iOS用户可升级到10.2。

对补丁进行比对,可以发现在漏洞函数OTL::GPOS::ApplyPairPos 中添加了判断【图5】,获取到的GlyphID值传递给OTL::Coverage::SearchFmt2Binary函数,当查找失败时会返回0,因此只要添加判断返回值是否为0,为0则直接跳走返回。



图5

处理流程

  1. 2016-10-23 通过邮件提交给Apple
  2. 2016-11-09 Apple确认漏洞,并在 macOS Sierra 10.12.2 beta 测试版中修复
  3. 2016-12-09 分配CVE号:CVE-2016-7595
  4. 2016-12-14 Apple发布安全公告,并推送补丁

2016年刷过的CVE

今年也开始尝试跟风刷CVE,主要是下半年才开始搞,开始聚集Google和Apple,Google Android 因为撞洞,最终连个CVE也没有,也是惨,只能寄希望于2017年了。革命尚未成功,同志仍需努力!

公司 产品 时间 类型 CVE号
/ libarchive 2016/12/29 Use After Free CVE-2016-10080
Apple macOS/iOS 2016/12/14 Out-of-Bounds CVE-2016-7595
Apple macOS/iOS 2016/12/14 Out-of-Bounds CVE-2016-4691
Apple macOS 2016/12/14 Memory Corruption CVE-2016-7618
Apple macOS 2016/12/14 Memory Corruption CVE-2016-7622
/ giflib 2016/12/13 Out-of-Bounds CVE-2016-9944
/ OpenJPEG 2016/12/07 Memory Corruption CVE-2016-9890
/ libxml2 2016/12/05 Out-of-Bounds CVE-2016-9833
/ OpenJPEG 2016/12/01 Memory Corruption CVE-2016-9753
Apple Mac OS X 2016/09/21 Memory Corruption CVE-2016-4779
Apple Xcode 2016/09/14 Memory Corruption CVE-2016-4705
/ libgd 2016/05/01 Double Free CVE-2016-4413
/ libav 2016/03/18 Memory Corruption CVE-2016-3184
/ libav 2016/03/11 Memory Corruption CVE-2016-3062
Adobe Flash Player 2016/03/11 Memory Corruption CVE-2016-0992

BlackHat USA 2016 议题分析

作者:riusksk(泉哥)
主页:http://riusksk.me
本文已发表于2016年9月CSDN的《程序员》杂志,转载请注明出处。



大会概述

BlackHat USA 是世界上最著名的黑客大会BlackHat的主场,规模远超亚洲、欧洲等分会,今年大约有15000人参会,依然在美国拉斯维加斯举办。

大会全程共6天,包括 Training 培训、Keynote 议题分享、Arsenal 工具展示以及素有”黑客奥斯卡“之称的 Pwnie Awards 颁奖。

今年有上百个议题入选,涉及的安全领域也是相当广泛全面,包括移动安全、物联网、软件安全、加密、工控、企业安全、Web安全、逆向工程、恶意软件等等,整体上跟往年的议题类型差不多。

每年的BlackHat USA都代表着一个安全技术发展的”风向标“,在这可以看到全球顶端安全研究人员的研究成果,以及业界安全发展趋势。不少政府人员,比如FBI经常会出现在会场,以前也有FBI在现场带走一些有犯罪记录的人员,或者禁止涉及过于敏感内容的演讲,但一般是在BlackHat的兄弟会议Defcon上下手,比如曾经某黑客在Defcon演讲完后,在回旅馆的路上被抓了,还有之前MIT学生破解波士顿地铁免费乘坐地铁的演讲也被禁止掉。

精彩议题分析

笔者针对BlackHat官网上公布的各个议题pdf筛选了一遍,挑选出一些大家可能感兴趣,或者技术新颖有兴趣的议题作简要介绍和点评。

1、《Using EMET to Disable EMET》——绕过微软EMET防护工具实现软件漏洞利用的方法



图1:禁用EMET前后LoadLibraryA函数入口代码的对比情况

该议题来自国外著名安全公司FireEye的分享,是一家专门为企业提供安全防护产品的公司,该公司曾发现许多0Day漏洞以及APT攻击事件。

【内容简介】

Microsoft’s Enhanced Mitigation Experience Toolkit (EMET)是一款针对用户程序的内存防护工具,可以提高软件的漏洞利用难度。
FireEye安全研究人员介绍了一种新型的禁用EMET技术,同时举例了一些以前针对EMET的攻击方式。他们介绍的新型绕过技术主要是利用ROP技术找到DLLMain函数入口,然后实现以下代码的调用:

1
BOOL WINAPI DllMain (GetModuleHandleA("EMET.dll") , DLL_PROCESS_DETACH , NULL);

EMET主要通过向保护的用户进程注入emet.dll或者emet64.dll,同时因为GetModuleHandleA 未被Hook,所以使用以上方法去卸载EMET.dll中的各种API Hook,虽然这不会将EMET从内存中移除,但已经足够禁用它的所有防护功能。

【点评】

在著名的黑客赛事Pwn2Own中,微软要求必须绕过EMET和沙盒保护攻下64位IE浏览器才算成功,因此绕过EMET成了攻破IE的必经之路。

不过,由于EMET并非默认在系统上开启的,需要用户自行安装,因此实际上使用EMET来保护系统软件的用户并不会太多,甚至包括一些安全人员也很少使用它,在诸多实际攻击案例中,大多不用绕过EMET就可以攻下系统。

fsmon:多平台文件监控工具

近日在Mac上跑测试,时间一长就硬盘空间就被占用完了,几小时就生成10多G文件,导致系统卡死,程序也没法继续运行,但一直没找到生成的文件路径。
于是在Github上找到fsmon (https://github.com/nowsecure/fsmon )这个工具,一款多平台下文件监控工具,最后终于找到生成垃圾文件的路径:/private/var/folders/,原来是QuickLook缓存文件,后面写个定时脚本清除即可。

Vulnerability War: The Essence of Software Vulnerabilities Analysis

By riusksk(@riusksk)

想出英文版的,但苦于目前出版社找不到译者,所以把内容简介和目录的英文版发出来给老外看,国内朋友如有有合适且有意愿的也欢迎留言!

Content Abstract

Vulnerability War: The Essence of Software Vulnerabilities Analysis systematically explain all kinds of tools, techniques and practical methods in software vulnerability analysis and exploit, mainly related to Windows and Android platform. The book is classfied according to the different vulnerabilities, such as stack overflow, sandbox escape, types confusion, UAF , kernel vulnerability etc., at the same time, in view of the current popular mobile security, add Android platform vulnerability analysis and exploit into it. The author carefully chosen classic Vulnerabilities to share analysis techniques and tools about the cause of these vulnerabilities analysis, exploit and fix methods in detail. The biggest characteristic of this book is the actual combat based on the various types of classical vulnerabilities and discard useless theory, it’s almost “a book written out by debugger”.

This book is suitable for students of computer science related, somebody worked in information security, software security and mobile security related areas, software developer and hackers to read.

Table of Contents

Chapter 1: Basic Knowledge

1.1 The Concepts of Vulnerability
1.1.1 What is The Vulnerability
1.1.2 The Value of Vulnerabilities
1.1.3 0day Vulnerability
1.1.4 PoC and Exploit
1.2 Why to analysis vunerabilities
1.3 The commonly analysis tools
1.3.1 IDA: the disassembly tool
1.3.2 OllyDbg: the crack and reverse analysis tool
1.3.3 Immunity Debugger: vulnerability analysis debugger
1.3.4 Windbg: Microsoft Windows Debugger
1.3.5 GDB: Linux Debugger
1.3.6 JEB: Android Decompilater
1.3.7 Other
1.4 The common vulnerability analysis method
1.4.1 Static analysis
1.4.2 Dynamic debugging
1.4.3 Source code analysis
1.4.4 Patch compare
1.4.5 Taint track
1.5 Learning resources
1.5.1 Some security sites
1.5.2 Recommended books
1.6 Summary

China-Pub计算机类图书畅销榜第一

当初编辑联系我出书时,我就曾提前对其说过这类书籍可能受众有限,而且非入门书籍,可能销量不会太理想。

同时自己觉得,现在安全入门书籍,无论是web还是二进制,其实都已经足够了,没必要再写。

若是纯粹地追求销量,而忽略书籍的本质内容,还是太对不起自己,也对不起读者,虽然排行磅前列的几名经常被《XXX从入门到精通》给霸占着。

所以,出书的初衷就是记录自己学习历程中点点滴滴,也是为了备忘,算是一本写给自己的书籍。

出版后,内心的梗算是放下了,但还是挺忐忑的,后来一位编辑说,基本每一本书的出版都会被骂,然后我就释怀了。

目前,新书的销售情况还算可观,已经准备再印了,比我想像中的要好,特别感谢各位业界同行的支持!

当然也有一些非技术的同学也买了,只因前言中的”情怀“,也感谢这些同学的支持。

《漏洞战争:软件漏洞分析精要》勘误表

后面会在github上维护一款《漏洞战争》的勘误表:https://github.com/riusksk/vul_wars_error ,会不定期更新,也欢迎各位读者通过微博@riusksk反馈书中的错误,等后面重印时更正,并在前言添加感谢。

当前错误列表

1、前言VIII 第4段落最后一句:专研 => 钻研
2、P7页中多处的 smail => smalibaksmail => baksmali (感谢 陈良@科恩实验室)
3、P529页第2段中,“按照图10-12所示的方法重新编译内核源码” => “按照第10.3.7章节的方法重新编译内核源码”(感谢 江小照)
4、P16页最后一行中Thread => Threat(感谢 “不高兴撒”)
5、P164页第3段第3行unsigned int(2字节) => unsigned int(4字符)(感谢 “55-AA”)

《漏洞战争:软件漏洞分析精要》已开售


购买地址 

China-Pub
京东
淘宝
当当
亚马逊

编辑推荐 

《漏洞战争:软件漏洞分析精要》是这些年来难得一见的系统、全面深入分析漏洞攻防心要与战术的书籍。《漏洞战争:软件漏洞分析精要》结合经典的漏洞案例,从攻防思路、分析方法与实战等方面对漏洞攻防做了详细的阐述。既照顾了全局的视野,又不失细节上的周到,对于有志于安全事业并想在安全技术分析上有所提升的读者,这是一本可信赖的必备书籍。正如wushi老师所说:”……对照本书动手调试这些经典漏洞,我相信只要认真做一遍,功力会大增。”
还犹豫什么呢,好书,一本就够!

内容简介

《漏洞战争:软件漏洞分析精要》系统地讲解软件漏洞分析与利用所需的各类工具、理论技术和实战方法,主要涉及Windows 和Android 系统平台。《漏洞战争:软件漏洞分析精要》根据不同的软件漏洞类型划分,比如堆栈溢出、沙盒逃逸、类型混淆、UAF、内核漏洞等,同时又针对当前流行的移动安全,加入Android 平台上的漏洞分析与利用。以精心挑选的经典漏洞为例,以分享漏洞的分析技巧和工具为主,对这些漏洞的成因、利用及修复方法进行详细讲解,旨在”授之以渔”。《漏洞战争:软件漏洞分析精要》最大的特点是以各种类型的经典漏洞作为实战讲解,摒弃空头理论,几乎是”一本用调试器写出来的书”。
《漏洞战争:软件漏洞分析精要》适合计算机相关专业的本科及研究生,信息安全爱好者,软件安全及移动安全相关的安全从业人员,软件开发与测试人员、黑客等阅读。