【技术分享】iOS 安全之针对 mach_portal 的分析

栏目: CSS · CSS3 · 发布时间: 7年前

内容简介:【技术分享】iOS 安全之针对 mach_portal 的分析

【技术分享】iOS 安全之针对 mach_portal 的分析

作者: shrek_wzw

预估稿费:800RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿

一. 背景

Google Project Zero的Ian Beer在12月中旬放出了在iOS 10.*上获取root shell的利用代码,意大利的Luca在此基础上添加了KPP绕过,实现了iOS 10.*的越狱。本文将结合mach_portal的源码对其利用的三个漏洞进行分析,并对每一个步骤进行说明。

mach_portal利用的漏洞都源于XNU内核对Mach Port的处理不当,相信这也是mach_portal名称的由来。XNU内核提供了多种进程间通信(IPC)的方法,Mach IPC就是其中的一种。Mach IPC基于消息传递的机制来实现进程间通信,关于Mach IPC的消息传递在众多书籍和文章中都有介绍,在此就不再赘述。我们这里介绍Mach Port。

Mach消息是在端口(Port)之间进行传递。一个端口只能有一个接收者,而可以同时有多个发送者。向一个端口发送消息,实际上是将消息放在一个消息队列中,直到消息能被接收者处理。

内核中有两个重要的结构,ipc_entry和ipc_object。ipc_entry是一个进程用于指向一个特定ipc_object的条目,存在于各个进程的ipc entry table中,各个进程间相互独立。

【技术分享】iOS 安全之针对 mach_portal 的分析

ipc_object就是ipc port或者ipc port set,实际上代表的就是一个消息队列或者一个内核对象(task,thread等等),Mach消息的传递就是通过ipc port的消息队列。ipc_object在内核中是全局的,一个ipc_object可以由不同进程间的ipc_entry同时引用。平常我们在编写代码时得到的Mach Port是一个32位无符号整型数,表示的是ipc_entry在ipc entry table中的索引值。经过MIG的转换后,在内核中,就可以从ipc_port得到实际的内核对象,例如convert_port_to_task等等。具体可以参考XNU源码和《Mac OS X Internals: A Systems Approach》,对于Mach IPC的相关数据结构有更为详细的说明。

【技术分享】iOS 安全之针对 mach_portal 的分析

二. 漏洞详情

mach_portal利用了三个漏洞,CVE-2016-7637、CVE-2016-7644、CVE-2016-7661。下面将对这三个漏洞的进行分析。

1. CVE-2016-7637

漏洞说明:内核对于ipc_entry的user reference处理不当,使得ipc_entry被释放后重用,导致特权port可能被替换成攻击者控制的port。(GPZ Issue 959)

漏洞分析:当一个进程接收到带有port的mach message时,函数调用的流程如下。

【技术分享】iOS 安全之针对 mach_portal 的分析

在ipc_right_copyout函数中,会将port right复制到当前task的ipc entry table中。ipc_entry的ie_bits的含义如下图。ie_bits的低16位为user reference,表示的当前ipc_entry的引用数量,最大值为0xFFFF。

【技术分享】iOS 安全之针对 mach_portal 的分析

当ipc_right_copyout处理 MACH_PORT_TYPE_SEND的port时,代码如下

【技术分享】iOS 安全之针对 mach_portal 的分析

可以看到,user references的值不会超过MACH_PORT_UREFS_MAX-1 = 0xFFFE。考虑这样一种场景,当前进程收到一个ool ports descriptor消息,当这条ool ports descriptor消息因为不符合接收进程的标准而被销毁时,以mach_msg_server为例,会调用mach_msg_destroy释放消息中带有的所有port right,如图。

【技术分享】iOS 安全之针对 mach_portal 的分析

ool ports descriptor被销毁时,会调用mach_msg_destroy_port释放每一个port right,更下层的函数会调用ipc_right_dealloc减少port对应的ipc_entry的一个引用(urefs)。当urefs等于0时,这个ipc_entry就会被释放到free list中,表示当前entry已经处于空闲状态,可以被申请用于指向另一个ipc_object。

【技术分享】iOS 安全之针对 mach_portal 的分析

如果消息中带有同一个port的0x10000个descriptor,那么在处理这个消息时就会使得当前这个port对应的ipc_entry的user reference到达上限0xFFFE。当被销毁时,这个ipc_entry就会被释放0x10000次,进而进入free list。然而,用户空间并不知道这个ipc_entry已经被释放,因为用户空间的进程保留的仅仅是一个32位的整型索引。当尝试用这个索引去访问ipc entry table对应位置的ipc entry时,就会出现问题。

攻击方式:利用这个漏洞,可以使高权限进程中的特权port的ipc_entry被释放,然后再利用我们拥有receive right的port重新占位(需要处理ipc_entry的generation number),使得原先发送到特权port的消息都会被发送到我们拥有receive right的port上,形成port消息的中间人攻击。

利用方法(macOS提权,Ian Beer提供的PoC的攻击流程):

(1)攻击目标是com.apple.CoreServices.coreservicesd服务(mach_portal的目标不同),launchd拥有这个服务的send right。

(2)攻击者通过漏洞使得launchd拥有的send right被释放。

(3)然后再利用launchd注册大量的服务,期望这些服务的port的ipc_entry会重用之前被释放的send right。 

(4)这样,当任意进程通过bootstrap port尝试查找coreservicesd的服务端口时,launchd就会将攻击者拥有receive right的端口发送给它。

(5)攻击者的进程拥有coreservicesd的send right。可以通过中间人(MiTM)的方式,来监听任意进程与coreservicesd的通信。

(6)通过获取root进程的task port,来得到root shell。

2. CVE-2016-7644

漏洞说明:在调用set_dp_control_port时,缺乏锁机制导致的竞争条件,可能造成ipc_entry指向被释放的ipc_port,形成UAF。(GPZ Issue 965)

漏洞分析:

set_dp_control_port源码如下

【技术分享】iOS 安全之针对 mach_portal 的分析

在调用ipc_port_release_send释放port的send right的时候,没有加锁。两个线程通过竞争条件,可以释放掉一个port的两个reference,使得ipc_entry指向被释放的ipc port。

利用方法(mach_portal):

(1) set_dp_control_port的第一个参数是host_priv,需要通过root权限的task获取

(2) 攻击者分配一个拥有receive right的port,插入send right引用(ipc_entry)。

(3) 利用port descriptor消息将这个port发送给自己,使内核拥有一个这个port的send right引用。

(4) 调用set_dp_control_port将这个port设置为dynamic_pager_control_port,拥有一个send right。

(5) 利用mach_port_deallocate释放自己的send right。这时,这个port的包含两个send right计数:port descriptor和dynamic_pager_control_port。包含三个引用计数:ipc_entry,port descriptor和dynamic_pager_control_port。

(6) 利用两个线程触发set_dp_control_port的竞争条件漏洞,使得引用数减少2。这时,这个port的send right计数为0,引用计数为1。但是仍然有两个指针指向这个port:ipc_entry,port descriptor。

(7) 再销毁之前发送的port descriptor消息,释放最后一个引用,使ipc_port被释放。形成ipc_entry指向一个被释放的ipc_port,利用其它数据占位这个被释放的ipc_port,即形成UAF。

3. CVE-2016-7661

漏洞说明:powerd对于DEAD_NAME通知的处理存在缺陷,导致攻击者指定的port在powerd进程中被释放,形成拒绝服务或port替换。(GPZ Issue 976)

漏洞分析:漏洞的详细分析参照Ian Beer的漏洞报告。这里简单说明一下漏洞的成因。

powerd进程创建pmServerMachPort用于接收相关的服务消息,同时在这个port上允许接收DEAD_NAME的通知。当接收到一条msgid为MACH_NOTIFY_DEAD_NAME时,就会从消息中的not_port字段取出port的值,然后调用mach_port_deallocate进行销毁。

【技术分享】iOS 安全之针对 mach_portal 的分析

之所以会造成漏洞,是因为这个DEAD_NAME通知的消息是简单消息(simple message)。简单消息的传递并不涉及底层ipc_port的引用计数的修改,这里的not_port仅仅是一个整型的数据,这就表示攻击者可以向mach_port_deallocate提供任意的port参数。如果这个port参数正好是powerd进程中合法的一个port,就会导致port的释放,例如当前进程的task port。一旦task port被异常释放掉,后续的一些以task port作为参数的函数调用极有可能失败。这时,若缺乏对失败函数的检查,就可能导致powerd进程崩溃。

攻击方法(mach_portal):

(1) powerd进程以root权限运行

(2) mach_portal的目的是导致powerd进程崩溃,再其重新启动后向launchd注册服务时,通过port中间人攻击,窃取其task port来获取host priv port。

(3) 具体的攻击方式如分析中所述,向powerd进程的服务端口发送DEAD_NAME通知消息,以0x103作为not_port的数值(在大多数情况下,0x103是mach_task_self的返回值),这就会导致powerd进程调用mach_port_deallocate释放掉自身的task port。

(4) 在调用io_ps_copy_powersources_info时,powerd进程就会通过vm_allocate,以task port作为参数尝试分配内存。由于task port已经被释放,这时vm_allocate分配内存失败。

(5) powerd缺少对于返回值的检测,就会访问一个非法的地址指针,导致powerd进程崩溃。

三. mach_portal源码文件

mach_portal包含了在10.*的设备上获取root shell的代码。下面简单说明一下源码中比较重要的各个文件的作用。

cdhash.c: 计算MachO文件的CodeDirectory SHA1 Hash

disable_protections.c: 将mach_portal进程提权至root,绕过沙盒的限制

drop_payload.c: 处理iosbinpack中的可执行文件,socket监听端口,生成shell

jailbreak.c: 越狱流程入口

kernel_memory_helpers.c: 获取kernel task port后,内核读写的接口封装

kernel_sploit.c: set_dp_control_port竞争条件的利用,用于获取kernel task port

offset.c: 包含设备以及系统相关的偏移量的初始化

patch_amfid.c: 利用amfid的exception port来绕过代码签名

sandbox_escape.c: 利用ipc_entry urefs和powerd的漏洞,获得host priv port,进一步攻击内核

unsandboxer.c: 利用bootstrap port在父子进程之间的继承,监听子进程和launchd的通信,获取子进程的pid,通过提权,使mach_portal的子进程也绕过沙盒

四. mach_portal攻击流程

mach_portal实现越狱的过程可以分为两个部分。第一个部分是利用上文提到的三个漏洞组合,获取到kernel task port,能够实现内核任意读写。第二部分是对于一些保护机制的绕过,包括沙盒、代码签名等等,由于仅仅是纯数据的修改,并不涉及任何代码片段的patch,不会触发KPP。

第一部分:

1. 利用漏洞 1 — CVE-2016-7637 释放launchd拥有的iohideventsystem port,实现MiTM。

2. 利用漏洞 3 — CVE-2016-7661 触发powerd崩溃,使得powerd将其task port发送给我们,得到拥有root权限的task port。

3. 利用powerd的task port,获取host priv port,触发漏洞 2 — CVE-2016-7644,实现内核exploit。

4. 通过内核exploit获得kernel task port,实现内核地址空间的任意读写。

第二部分:

1. 得到内核空间的任意读写权限后,就能够实现对任意进程地址空间的任意读写(能够从proc list得到任意进程的task port)。

2. 利用内核读写将本进程(mach_portal)的credential设置成kernproc的credential,实现提权和沙盒的绕过。

3. 将containermanagerd的credential也设置成kernproc的credential。

4. 将kernel task port设置成host special port 4,便于其他 工具 通过host_get_special_port获取kernel task port。

5. 恢复第一部分中用于中间人攻击的launchd的iohideventsystem的port为原始的port,并再次触发powerd崩溃,修复powerd进程对于iohideventsystem的send right。

6. 利用amfid的task port,调用task_set_exception_ports,将amfid的exception port设置成我们拥有receive right的port,并修改amfid的导入表,将MISValidateSignatureAndCopyInfo的导入地址设置成非法的地址。这样,当进行代码签名验证的时候,就会触发异常并将异常信息发送到我们的端口。我们对异常信息进行处理,并自行计算MachO CodeDirectory的SHA1 Hash后将其写入amfid的地址空间,最后修复amfid中引起异常的线程的状态。成功绕过amfid的代码签名检查,可以执行任意未签名的MachO文件。

7. 为了能够监听端口,生成shell,需要子进程也拥有root权限、绕过沙盒。这里利用子进程创建时会从父进程继承bootstrap port的特点。首先调用task_set_special_port将自身的bootstrap port设置成新申请的fake bootstrap port,这时创建的所有子进程就会继承这个fake bootstrap port。父进程利用port中间人攻击的方法,监听子进程和launchd的通信,获取子进程的pid后,修改对应pid的内核proc结构的credential为kernproc的credential,实现子进程的提权和沙盒绕过。

8. 最后的部分,处理iosbinpack中的可执行文件的路径,设置权限。生成PATH环境变量的路径,创建socket绑定端口。在接收外部连接后,调用posixspawn运行bash,重定向标准输入、标准输出和标准错误至socket的fd,实现bind shell。这时,外部连接就能够通过nc连接对应的端口,以root的权限通过bash shell访问文件系统。

五. mach_portal部分利用细节

下面将会详细说明其中内核利用部分一些比较重要的实现细节。盘古团队在1月5日的博客中也解释了这些细节(http://blog.pangu.io/mach-portal-details/),可以参考。结合mach_portal和XNU的源码,相信也能够有更好的理解。我这里只是抛砖引玉,阐述自己的理解。

1. ipc_entry索引复用

触发CVE-2016-7637针对ipc_entry的漏洞时,涉及ipc_entry索引的复用。ipc_entry的索引就是用户空间观察到的mach port name,一个32位的整型。这个32位整型分为两部分,高24位(index)和低8位(generation number)。

【技术分享】iOS 安全之针对 mach_portal 的分析

详情参见源码ipc_entry.c。当调用ipc_entry_alloc分配一个新的ipc_entry时,会从对应的ipc entry table的位置上取出ie_bits,在原来的generation number的基础上加上4。

【技术分享】iOS 安全之针对 mach_portal 的分析

【技术分享】iOS 安全之针对 mach_portal 的分析

【技术分享】iOS 安全之针对 mach_portal 的分析

同一个ipc_entry的name索引(高24位)始终不变。但generation number仅仅占用8位,因此这个ipc_entry被分配 256 / 4 = 64 次后,返回给用户空间的name就会相同,实现ipc_entry的复用。

mach_portal攻击launchd的代码见sandbox_escape.c。mach_portal攻击的是launchd进程拥有的com.apple.iohideventsystem的send right(mach port name)。操作launchd中的ipc_entry的分配和释放的代码见send_looper函数,调用一次send_looper函数,就会在launchd进程中申请一定数量的ipc_entry后再释放。

劫持流程如下:

① mach_portal触发漏洞释放com.apple.iohideventsystem对应的ipc_entry后,这时ipc_entry位于free list的第一个。

② 调用send_looper向launchd发送0x100个port,就会首先占用目标ipc_entry,然后再从free list取出其他ipc_entry进行占用。

③ 当这0x100个port被释放的时候,会按照在port descriptor消息中的顺序进行释放。我们的目标ipc_entry由于最先被释放,根据free list LIFO的特点,因此会位于free list第0x100左右的位置。(完成1次)

④ 接下来的62次调用send_looper,发送0x200个port进行launchd进程的ipc_entry的分配和释放,可以保证目标ipc_entry在被释放后始终位于free list 0x100左右的位置。(完成62次)

⑤ 最后我们向launchd注册大量app group的服务(由于iOS注册服务的限制,这里注册app group的服务),提供我们拥有receive right的port作为这些服务的port。经过3和4两个步骤后,已经完成了63次的分配和释放。当我们向launchd注册大量的服务时,相当于第64次进行ipc_entry的分配和释放,使得目标ipc_entry被成功复用,并且指向的是我们拥有receive right的port。

⑥ 任意进程向launchd申请com.apple.iohideventsystem的port时,launchd就会将我们的port的发送给请求者进程。通过接收port上的消息,进行监听处理后,将其转发给真正的服务port,从而实现中间人攻击。

2. Port中间人攻击

port消息的中间人攻击也是mach_portal的一个亮点。当我们劫持了launchd进程中的com.apple.iohideventsystem的对应的port后,任意进程向com.apple.iohideventsystem发送的消息都会经过我们拥有的port。

我们当前拥有com.apple.iohideventsystem的真实port,通过劫持port接收到的消息需要继续转发给真正的服务port,以维持系统的正常运行。攻击者的目的是从发送的消息中监听所有可能被发送出来的task port,并在这些task port上调用task_get_special_port函数,尝试获取host priv port,只要成功获取,目标(触发下一阶段的竞争条件漏洞需要host priv port)就以达到,见inspect_port函数。

具体实现见sandbox_escape.c的do_service_mitm函数。函数流程如下:

【技术分享】iOS 安全之针对 mach_portal 的分析

3. 跨zone的port UAF利用

set_dp_control_port的竞争条件漏洞的利用代码位于kernel_sploit.c文件中,目标是获取kernel task port。总体流程如下:

【技术分享】iOS 安全之针对 mach_portal 的分析

由于ipc_port位于独立的ipc.ports zone中,因此无法按照过往的heap spray的方式进行kalloc zone占位利用。

首先通过分配大量的port并使得其中0x20个middle port通过set_dp_control_port漏洞减少其引用数。这时,当前进程的ipc_entry状态如下(便于理解,port处于连续位置):

【技术分享】iOS 安全之针对 mach_portal 的分析

一个port的引用数为1,但是被两个指针指向。释放ool ports descriptor后并触发mach zone gc后,内存状态如下:

【技术分享】iOS 安全之针对 mach_portal 的分析

发送包含host priv port的ool ports descriptor消息。内核对于mach msg中MACH_MSG_OOL_PORTS_DESCRIPTOR的处理代码见ipc_kmsg_copyin_ool_ports_descriptor函数,内核会调用kalloc重新分配页面,这时被攻击者释放的pages就会被重新使用,并填充ool ports descriptor的消息。内核会将对应位置的mach port name转化成对应的内核对象指针,如下图代码所示。在mach_portal的利用中,这里的object就是host priv port的内核ipc_port。

【技术分享】iOS 安全之针对 mach_portal 的分析

这时,内存的状态处于下图的类似状态(简图),在ool ports descriptor的特定位置设置host priv port name,其余port保持为0。

【技术分享】iOS 安全之针对 mach_portal 的分析

具体到每一个ipc_port块所对应的情况如下:

【技术分享】iOS 安全之针对 mach_portal 的分析

ip_context是ipc_port可以在用户空间访问的变量。用户空间可以通过调用mach_port_get_context得到,通过mach_port_set_context进行设置。

【技术分享】iOS 安全之针对 mach_portal 的分析

通过在悬垂的ipc_port指针上调用mach_port_get_context,就会将上图中绿色部分的host priv port的指针返回给用户空间,实现了内核信息泄露。

因为host priv port和kernel task port都是在系统启动阶段分配,并且时间临近,因此在host priv port的地址附近,可能存在kernel task port。mach_portal就根据这个特点进行猜测,将可能的地址数值通过mach_port_set_context,设置到悬垂的ipc_port指针指向的区域中,修改原有的ool ports message的对象指针。

最后,mach portal在用户空间接收这些被修改的ool ports message。与内核接收MACH_MSG_OOL_PORTS_DESCRIPTOR时的处理(port_name To object_ptr)相反,内核会将port地址转换成port name返回给用户空间(object_ptr To port_name)。如果这些猜测的地址中包含真正的kernel task port的地址,那么用户空间就会从ool ports message中得到其对应的port name。通过pid_for_task检查得到的task port的pid是否为0,即可判断是否成功获取了kernel task port。

References

2. CVE-2016-7637 By Ian Beer https://bugs.chromium.org/p/project-zero/issues/detail?id=959

3. CVE-2016-7644 By Ian Beer https://bugs.chromium.org/p/project-zero/issues/detail?id=965

4. CVE-2016-7661 By Ian Beer https://bugs.chromium.org/p/project-zero/issues/detail?id=976

5. Mac OS X Internals: A Systems Approach

6. mach portal漏洞利用的一些细节 by Pangu http://blog.pangu.io/mach-portal-details/

【技术分享】iOS 安全之针对 mach_portal 的分析 【技术分享】iOS 安全之针对 mach_portal 的分析

本文由 安全客 原创发布,如需转载请注明来源及本文地址。

本文地址:http://bobao.360.cn/learning/detail/3740.html


以上所述就是小编给大家介绍的《【技术分享】iOS 安全之针对 mach_portal 的分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Numerical Methods and Methods of Approximation in Science and En

Numerical Methods and Methods of Approximation in Science and En

Karan Surana / CRC Press / 2018-10-31

ABOUT THIS BOOK Numerical Methods and Methods of Approximation in Science and Engineering prepares students and other readers for advanced studies involving applied numerical and computational anal......一起来看看 《Numerical Methods and Methods of Approximation in Science and En》 这本书的介绍吧!

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

在线压缩/解压 JS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码