利用蓝牙callback逃逸iOS沙箱

iOS的Sandbox和IPC机制

iOS的sandbox限制了普通的应用程序只能访问自身沙箱内的资源,应用程序在进行系统调用时会受到sandbox的策略限制。因此,为了实现权限提升,逃逸iOS的sandbox是必要的。

iOS系统提供了IPC机制(进程间通信),如URL schemes, Mach, pipes等,Mach IPC是一套面向消息的IPC机制,实现对象与对象之间的通信,源对象发送一条消息,这条消息加入到目标对象的队列中等待处理。如果产生应答,则通过另一条消息传递回去。
消息分简单消息和复杂消息,分别对应两种不同的结构:

  • 简单消息

upload successful

  • 复杂消息

upload successful

Mach对象之间的消息时基于端口传递的,消息从某一个端口发送到另一个端口。向一个端口发送消息实际上是将消息放在队列中,直到消息被处理。查找一个对象的句柄(标识应用程序中的不同对象和同类中的不同的实例的值),实际上查找的是这个对象端口的句柄,给定一个对象的端口,就可以通信了。Mach消息传递使用的是Mach_msg()函数。

基于Mach的消息机制,iOS又提供了XPC、NSXPC等进程间通信机制,通过这些机制,sandbox内的应用可以和没有sandbox的Mach service进行通信,如果这些service在处理消息时发生错误,就有可能出现由sandbox到非sandbox的代码执行。

为了发现这些问题,我们将目标放在Mach service的消息处理上,那么如何找到实现Mach service的binary文件呢?

/System/Library/LaunchDaemons的plist文件包含了大多数Mach service,其中MachServices字段指向了一组Mach services,ProgramArguments字段指向实现这些Mach service的binary文件。

upload successful

CVE-2018-4087—— 利用bluetoothd绕过sandbox

com.apple.server.bluetooth是众多Mach service的其中一个,它由bluetoothd来实现,并通过Mach消息机制与普通的应用程序进行通信。

bluetoothd启动一个端口并在该端口接收队列的消息,其处理逻辑由apple_bluetoothd_mig_server函数实现,

upload successful

apple_bluetoothd_mig_server根据接收到的消息的msgid执行不同的callback函数,漏洞作者给所有的callback函数加上了符号,如下图:

upload successful

mach__BTLocalDeviceAddCallbacks是msgid为3时对应的callback,它主要实现注册一个回调函数的功能,回调函数的地址由消息的发送方给出。当触发相应的事件时,控制流即走向了回调函数。

upload successful

理论上讲,当一个对象与bluetoothd建立连接时,需要产生一个session token, bluetoothd根据这个token来判断收到的消息是不是来自这个对象。但是bluetoothd的session token值为mach_port_t类型,意味着这个值是很容易爆破的(0x0000 -0xFFFF)。

获得session后就挟持其他对象和bluetoothd的通信了,结合上述注册回调函数的功能,不难看出,我们可以冒充其他对象注册回调函数,即控制代码由bluetoothd走到一个任意回调函数,从汇编角度讲,我们通过挟持其他对象和bluetoothd的通信控制了PC。

为了实现sandbox逃逸,这个回调函数地址应该位于一个unsandbox进程中,作者给出了所有在bluetoothd上注册callback的unsandbox进程:
SpringBoard
mDNSResponder
aggregated
wifid
Preferences
CommCenter
iaptransportd
findmydeviced
routined
UserEventAgent
carkitd
mediaserverd
bluetoothd
coreduetd

[引文1](https://weibo.com/ttarticle/p/show?id=2309404271293301154324#_0)中给出了两幅图很形象的展示了这个攻击过程:

upload successful

upload successful

作者提供的PoC:https://github.com/rani-i/bluetoothdPoC/blob/master/bluetoothdPoC/main.m 该漏洞在iOS – 11.2.5上完成修复。

再次发现bluetoothd漏洞并利用

iOS 11.2.5修复了上述漏洞,通过增加了一个随机的user_id字段作为鉴别通信的依据。如下图所示:

upload successful

然而,研究人员通过分析,又发现两个新的0day。bluetoothd中的BTAccessoryManagerAddCallbacks()并没有实现user_id验证机制,这意味着依然可以使用上述漏洞。

但是BTAccessoryManagerAddCallbacks只有在蓝牙连接到一个新设备上时才会触发,研究人员又发现了在蓝牙扫描程序中的一个新bug,一个sandbox应用可以通过BTDiscoveryAgentCreate()创建一个扫描代理,并通过BTDiscoveryAgentStartScan() 去触发BTAccessoryManagerAddCallbacks事件。

这两个漏洞(CVE-2018-4330 and CVE-2018-4327)在iOS 11.4.1中被修复。

漏洞的进一步利用

从控制PC到ROP

利用上述漏洞仅仅能控制PC,为了实现RCE我们需要进一步布局,这里利用了ROP和堆喷射。作者提到使用了MACH_MSGH_BITS_COMPLEX 和 MACH_MSG_OOL_DESCRIPTOR Mach消息实现了堆喷,如果发送这类消息没有收到任何回复,则消息内容将会留存在目标进程的内存空间。

upload successful

为了挟持程序流,我们还需要操纵栈寄存器,即实现stack pivot。

作者在libsystem_platform.dylib发现一条ROP链,通过控制了X0寄存器进而达到了控制SP。

upload successful

从ROP到task port

在iOS中,一个进程的task port可以被用来控制该进程的内存和寄存器,task port通过mach_task_self()来获取,第三方进程可以通过这个task port去操纵目标进程,例如:
mach_vm_allocate(target_task_port, &remote_addr, remote_size, 1) 可以在目标进程中分配内存,mach_vm_write(target_task_port, remote_address, local_address, length)可以向目标进程中写入数据。

因此,unsandbox进程被控制后,将其task port发送给sandbox进程,sandbox进程进而实现了完全控制。具体实现如下:
pwn app使用mach_port_allocate()分配0x1000个port,并使用mach_port_insert_right() 在这些port中插入send right,之后通过MACH_MSG_PORT_DESCRIPTOR类型的OOL 消息发送到目标进程。下一步通过堆喷和ROP对内存布局,触发漏洞后控制PC,目标进程将task port返回给pwn app。

整个过程如下图:
upload successful

遗憾的是,iOS 11限制了sandbox进程对task port的访问,这种方法已经不再适用。

另一种方案

即使不能用task port,利用ROP已经实现了代码执行,再寻找其他的garget实现任意函数调用。

upload successful

这里作者并没有细说,期待更多的技术细节。

参考:

  1. https://weibo.com/ttarticle/p/show?id=2309404271293301154324#_0: Escaping sandbox using callbacks)
  2. Hack in the (sand)Box
  3. Mach消息发送机制
  4. Mining_Mach_Services_within_OS_X_Sandbox