CVE-2019-8635:macOS提权及任意代码执行漏洞分析

栏目: 编程工具 · 发布时间: 5年前

内容简介:我们在macOS中发现了一个双重释放(double free)漏洞(编码为这个CVE编号实际上覆盖了两个缺陷:

CVE-2019-8635:macOS提权及任意代码执行漏洞分析

0x00 前言

我们在macOS中发现了一个双重释放(double free)漏洞(编码为 CVE-2019-8635 ),该漏洞由AMD组件的内存破坏缺陷所导致。如果成功利用该漏洞,攻击者可以实现权限提升,以 root 权限在系统上执行恶意代码。我们向Apple反馈了漏洞情况,厂商后面也发布了相应 补丁

这个CVE编号实际上覆盖了两个缺陷: discard_StretchTex2Tex 方法以及 AMDRadeonX400_AMDSIGLContext 这个AMD Radeon类中对边带令牌(sindeband token)的 处理逻辑AMDRadeonX400_AMDSIGLContext 派生自 IOAccelGLContext2 类,而后者由 IOAccelContext2 类扩展而来。这些类用来在macOS主机上渲染图像。

漏洞位于 discard_StretchTex2Tex 以及 AMDSIGLContext::process_StretchTex2Tex 函数中,这两个函数是 AMDRadeonX4000_AMDSIGLContext 类的函数,我们可以使用 AMDRadeonX4000_AMDSIGLContext userclient以及selector 2对应的函数 IOAccelContext2::submit_data_buffers 来访问这个类,使用connect type 1来打开 AMDRadeonX4000_AMDGraphicsAccelerator 客户端。

0x01 AMDRadeonX4000_AMDSIGLContext discard_StretchTex2Tex双重释放权限提升漏洞

攻击者可以利用该漏洞在用户空间上执行代码。为了利用该漏洞,攻击者首先必须具备在目标macOS系统上执行低权限代码的能力。

该缺陷是因为系统没有对用户提供的数据进行适当的验证,导致读取操作超出已分配数据结构的末尾地址。攻击者可以利用这一点,再与其他漏洞结合起来,将权限提升至内核级别。

0x02 AMDRadeonX4000_AMDSIGLContext双重释放权限提升漏洞

同一个AMD类对边带令牌的处理过程中也存在一个双重释放漏洞。本地攻击者可以利用该漏洞在受影响的macOS上执行任意命令。与上一个漏洞一样,攻击者首先必须具备在目标系统上执行低权限代码的能力,才能进一步利用该漏洞。

虽然前一个漏洞位于 AMDRadeonX4000_AMDSIGLContext:discard_StretchTex2Tex 函数中,但这个漏洞位于 AMDRadeonX4000_AMDSIGLContext::process_StretchTex2Tex 函数中。漏洞成因在于系统在对目标对象执行操作前,没有去验证该对象是否存在。攻击者可以利用该漏洞将权限提升至内核级别。

从本质上讲,这两个漏洞在可能的利用途径方面比较相似,但在于具体利用的函数方面有所区别。

0x03 漏洞分析

CVE-2019-8635:macOS提权及任意代码执行漏洞分析

CVE-2019-8635:macOS提权及任意代码执行漏洞分析

图1. AMDRadeonX4000_AMDSIGLContext: discard_StretchTex2Tex 函数伪代码片段(上图), AMDRadeonX4000_AMDSIGLContext::process_StretchTex2Tex 函数伪代码片段(下图)

如图1(上图)所示,如果 (cmdinfo+32) 等于 0x8c00 ,那么 IOAccelResource v10 以及 v11 都会从 IOAccelShared2 中取值,对应的索引分别为 *(shareMem_start_address_187_offset16+8) 以及 *(shareMem_start_address_187_offset16+12) 。该函数随后会使用 IOAccelResource2::clientRelease() 函数来释放两个加速器资源。然而攻击者可以从用户空间中,通过内存映射,使用 IOAccelContext2 userclient来直接控制这两个索引。如果用户空间为 lookupResource 函数映射相同的索引,那么 clientRelease 就会两次释放相同的资源客户端,此时就会出现双重释放漏洞。

如图1(下)所示,如果 v15 等于 0x8c00 ,那么 accelResource_offset8 以及 accelResource_offset12 都会从 IOAccelShared2 中取值,以共享内存偏移24及28的值作为索引。最终,该函数会从 IOAccelShared2 _rst 释放 accelResource_offset12 ,如果 accelResource_offset8->member2 不等于 10 ,该函数也会从 IOAccelShared2 释放 accelResource_offset8 。然而将共享内存偏移24及28对应的值设成相同值,就会导致系统两次释放同一个 accelResource

process_StretchTex2Tex() 函数中,完成stretch操作时会使用 IOAccelResource2::clientRelease() 函数来释放两个资源客户端。然而,这两个 accelResource2 源自 AMDRadeonX4000_AMDSIGLContext 类中的 accelShare2 共享内存,使用对应的索引通过 IOAccelShared2::lookupResource 函数来获取。攻击者可以从用户空间中,通过 IOAccelContext2 用户客户端,利用内存映射来控制这些索引值。如果用户空间对 lookupResource 函数映射相同的索引,那么 clientRelease 就会两次释放相同的资源客户端,最终出现双重释放漏洞。

根据这两处代码执行流,共享内存地址指向的都是 commandStreamInfo + 24 。然而, commandStreamInfo 缓冲区实际上在 IOAccelContext2::processSidebandBuffe 函数中设置,如下图所示。在图2中, v5 指向的是 shareMem + 16 ,而 this->member196 指向的是 commandStreamInfo + 24

CVE-2019-8635:macOS提权及任意代码执行漏洞分析

图2. IOAccelContext2::processSidebandBuffer 伪代码片段

IOAccelContext2::clientMemoryForType 函数的伪代码片段如图3所示。该函数由已知的 IOConnectMapMemory64 API来调用,而后者会将一个用户缓冲区映射到内核空间中。在使用 IOConnectMapMemory64 函数时,我们需要设置连接对象、内存类型以及其他一些参数。此处连接对象为 IOAccelContext2 的实例,内存类型为 0 ,如图3所示。当我们将内存类型设置为 0 时, clientMemoryForType 函数会创建一个缓冲区内存描述符,返回用户空间的起始地址。此外,该函数还会将缓冲区内存地址设置为 shareMem_start_vm_address_187 变量(我们设置的变量名,非原始代码使用的变量名),该变量实际上正是在 IOAccelContext2::processSidebandBuffer 函数中使用的值。

根据该代码流程,我们可以控制共享缓冲区,以类似的方式设置这两个资源索引,随后触发双重释放漏洞。

CVE-2019-8635:macOS提权及任意代码执行漏洞分析

图3. IOAccelContext2::clientMemoryForType 函数伪代码片段

应用崩溃日志中的回溯信息如下所示,其中如果使用 discard_StretchTex2Tex 函数,那么只有 AMDRadeonX4000 AMDRadeonX4000_AMDSIGLContext::process_StretchTex2Tex 以及 process_StretchTex2Tex(IOAccelCommandStreamInfo&) + 2893`函数偏移有所区别。

* thread #1, stop reason = signal SIGSTOP
frame #0: 0xffffff7f8d7adc37 IOAcceleratorFamily2`IOAccelResource2::clientRelease(IOAccelShared2*) + 13
frame #1: 0xffffff7f8d880dad AMDRadeonX4000`AMDRadeonX4000_AMDSIGLContext::process_StretchTex2Tex(IOAccelCommandStreamInfo&) + 2893
frame #2: 0xffffff7f8d79b5d5 IOAcceleratorFamily2`IOAccelContext2::processSidebandBuffer(IOAccelCommandDescriptor*, bool) + 273
frame #3: 0xffffff7f8d8885e4 AMDRadeonX4000`AMDRadeonX4000_AMDSIGLContext::processSidebandBuffer(IOAccelCommandDescriptor*, bool) + 182
frame #4: 0xffffff7f8d79bae7 IOAcceleratorFamily2`IOAccelContext2::processDataBuffers(unsigned int) + 85
frame #5: 0xffffff7f8d7a2380 IOAcceleratorFamily2`IOAccelGLContext2::processDataBuffers(unsigned int) + 804
frame #6: 0xffffff7f8d798c30 IOAcceleratorFamily2`IOAccelContext2::submit_data_buffers(IOAccelContextSubmitDataBuffersIn*, IOAccelContextSubmitDataBuffersOut*, unsigned long long, unsigned long long*) + 1208
frame #7: 0xffffff800b027a3c kernel.development`::shim_io_connect_method_structureI_structureO(method=, object=, input=, inputCount=, output=, outputCount=0xffffff8742023968) at IOUserClient.cpp:0 [opt]
frame #8: 0xffffff800b025ca0 kernel.development`IOUserClient::externalMethod(this=, selector=, args=0xffffff87420239b8, dispatch=0x0000000000000000, target=0x0000000000000000, reference=) at IOUserClient.cpp:5459 [opt]
*frame #9: 0xffffff800b02ebff kernel.development`::is_io_connect_method(connection=0xffffff80b094e000, selector=2, scalar_input=, scalar_inputCnt=, inband_input=, inband_inputCnt=136, ool_input=0, ool_input_size=0, inband_output=””, inband_outputCnt=0xffffff80b0d81e0c, scalar_output=0xffffff8742023ce0, scalar_outputCnt=0xffffff8742023cdc, ool_output=0, ool_output_size=0xffffff80ab5c7574) at IOUserClient.cpp:3994 [opt]
frame #10: 0xffffff7f913044c2
frame #11: 0xffffff800a9bbd64 kernel.development`_Xio_connect_method(InHeadP=, OutHeadP=0xffffff8742023ce0) at device_server.c:8379 [opt]
frame #12: 0xffffff800a88d27d kernel.development`ipc_kobject_server(request=0xffffff80ab5c7400, option=) at ipc_kobject.c:359 [opt]
frame #13: 0xffffff800a859465 kernel.development`ipc_kmsg_send(kmsg=0xffffff80ab5c7400, option=3, send_timeout=0) at ipc_kmsg.c:1832 [opt]
frame #14: 0xffffff800a878a75 kernel.development`mach_msg_overwrite_trap(args=) at mach_msg.c:549 [opt]
frame #15: 0xffffff800a9f63a3 kernel.development`mach_call_munger64(state=0xffffff80af471bc0) at bsd_i386.c:573 [opt]
frame #16: 0xffffff800a823486 kernel.development`hndl_mach_scall64 + 22

当Mac系统出现内核错误(kernel panic)时,panic文本会被添加到日志中。 kernel panic 指的是内核检测到的系统错误,根源在于内核代码中没有对处理器异常进行处理(比如引用了无效的内存地址,或者调用链中出现错误,可以对比用户空间代码检测到的错误)。panic日志如下所示:

panic(cpu 6 caller 0xffffff800aa1391c): Kernel trap at 0xffffff7f8d7adc37, type 14=page fault, registers:
CR0: 0x0000000080010033, CR2: 0x0000000000000018, CR3: 0x0000000fea85f063, CR4: 0x00000000001626e0
RAX: 0x0000000000000000, RBX: 0xffffff800b473e28, RCX: 0x00000000ffffffff, RDX: 0x0000000000000000
RSP: 0xffffff8742023610, RBP: 0xffffff8742023610, RSI: 0xffffff80b0f8e470, RDI: 0xffffff80afa29300
R8: 0x0000000000000229, R9: 0xffffff800b2c4d00, R10: 0xffffff800b2c2c70, R11: 0x0000000000000058
R12: 0xffffff87299cb9b4, R13: 0x0000000000000001, R14: 0xffffff80b094e608, R15: 0xffffff80b094e000
RFL: 0x0000000000010282, RIP: 0xffffff7f8d7adc37, CS: 0x0000000000000008, SS: 0x0000000000000010
Fault CR2: 0x0000000000000018, Error code: 0x0000000000000002, Fault CPU: 0x6, PL: 0, VF: 0

与此同时,寄存器调试信息中关于kernel panic的信息如下所示。 $r12 寄存器指向的是共享内存地址 + 16 ,资源索引值也为 0x42

(lldb) register read
General Purpose Registers:
rax = 0x0000000000000000
rbx = 0xffffff800b473e28 kernel.development`kdebug_enable
rcx = 0x00000000ffffffff
rdx = 0x0000000000000000
rdi = 0xffffff80afa29300
rsi = 0xffffff80b0f8e470
rbp = 0xffffff8742023610
rsp = 0xffffff8742023610
r8 = 0x0000000000000229
r9 = 0xffffff800b2c4d00 kernel.development`zone_array + 8336
r10 = 0xffffff800b2c2c70 kernel.development`zone_array
r11 = 0x0000000000000058
r12 = 0xffffff87299cb9b4
r13 = 0x0000000000000001
r14 = 0xffffff80b094e608
r15 = 0xffffff80b094e000
rip = 0xffffff7f8d7adc37 IOAcceleratorFamily2`IOAccelResource2::clientRelease(IOAccelShared2*) + 13
rflags = 0x0000000000010282
cs = 0x0000000000000008
fs = 0x00000000ffff0000
gs = 0x00000000afa20000

(lldb) x/20g $r12
0xffffff87299cb9b4: 0x00000364001a8c00 0x0000004200000042
0xffffff87299cb9c4: 0x0000104000000101 0x0055550000900002
0xffffff87299cb9d4: 0x0004000800040008 0x1048000000010001
0xffffff87299cb9e4: 0x0055560000900002 0x0002000800020008
0xffffff87299cb9f4: 0x0000000000010001 0x0000000000000000
0xffffff87299cba04: 0x0000000400000004 0x0000000000000000
0xffffff87299cba14: 0x0000000200000002 0x00000364001a8c00
0xffffff87299cba24: 0x0000004200000042 0x0000104800000101
0xffffff87299cba34: 0x0055560000900002 0x0002000800020008
0xffffff87299cba44: 0x1050000000010001 0x0055570000900002

0x04 缓解措施

攻击者可以使用双重释放漏洞来攻击未打补丁的macOS系统,成功在目标主机上获取较高权限。Apple已推出安全补丁,改进内存处理机制来修复内存破坏问题。macOS Mojave 10.14.4已经可以使用最新补丁,大家应当尽快 更新 系统。此外,大家也可以安装类似 Trend Micro Antivirus for Mac 以及 Trend Micro Protection Suites 之类的解决方案来检测并阻止使用利用各种缺陷的攻击行为。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

知识的边界

知识的边界

[美] 戴维·温伯格 / 胡泳、高美 / 山西人民出版社 / 2014-12-1 / 42.00元

大数据时代反思知识 因为事实不再是事实,专家随处可见 所有确定性都被连根拔起,话题再无边界,没有人对任何事情能达成一致。 在互联网的引领下,知识现在已经具有了社交性,流动且开放。温伯格向我们展示了这些特点如何可以为我们所用。 ——马克•贝尼奥夫(云计算之父,著有《云攻略》) 这本富有洞见的著作,奠定了温伯格作为数字时代最重要的思想家之一的地位。如果你想要理解信息洪流涌......一起来看看 《知识的边界》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具